**************************************** * * * GameBasic User's Guide - Version 1.1 * * * **************************************** _________________________________________________________________ _________________________________________________________________ All rights reserved. Basic and QBasic are registered trademarks of Microsoft Corp. Commercial games and other products named in this document are the trademarks of their respective owners and are used in an editorial fashion only, to the benefit of their respective trademark owners, with no intention of infringement of the trademarks. Copyright (c) 1994 Michael R. Watts _________________________________________________________________ _________________________________________________________________ Table of Contents _________________ 1: Welcome to GameBasic. 1.1 What is GameBasic? 1.2 System Requirements 1.3 Installing GameBasic 1.4 How do you make games with GameBasic? 2: Files and Directories 3: QBasic Programming Environment. 3.1 Introduction 3.2 Starting QBasic 3.3 QBasic Programming Environment - a TOUR 3.3.1 FILE - OPEN Option 3.3.2 EDITING a Basic program 3.3.2.1 Entering text with Insert ON/InsertOFF 3.3.2.2 Creating blank program lines 3.3.2.3 Deleting characters/whole lines 3.3.2.4 Moving/Copying /Deleting blocks of lines 3.3.3 FILE - SAVE AS Option 3.3.4 FILE - SAVE Option 3.3.5 FILE - NEW Option 3.3.6 RUN - START Option 3.3.7 EXITING QBasic 3.4 OTHER Qbasic Options/HELP 4: Learning Basic programming. 4.1 Flowcharting 4.2 Variables in Basic 4.2.1 Numeric Variables 4.2.2 Using variables in calculations 4.2.3 Alphabetic (STRING) variables Basic commands 4.3 - CLS (Clear screen) 4.4 - INPUT 4.5 - PRINT 4.6 - LOCATE 4.7 - IF . . . THEN . . . ELSE 4.8 - GOSUB 4.9 - DO WHILE .... LOOP 4.10 - FOR ..... NEXT 4.11 - CALL Basic Arrays 4.12 - DIM 4.13 - REDIM 4.14 - Debugging your program 5: GameBasic Commands 5.1 Introduction 5.2 Gamebasic Base program 5.3 CHAR$ 5.4 CALL DEFINECHAR 5.5 CALL CREATE 5.6 CALL MOVE 5.7 INKEY 5.8 CALL CONTROL 5.9 CALL SHOOT 5.10 CALL ACTIVE 5.11 CALL CHECKHIT 5.12 CALL DELETE 5.13 CALL INFO 5.14 CALL RAND 5.15 CALL CHANGECHAR 6: Additional Gamebasic Commands. 6.1 CALL MOTION 6.2 CALL GETANGLE 6.3 CALL MUSIC 6.4 CALL TEXTSCREEN 6.5 CALL QUESTION 6.6 CALL TRACK 6.7 CALL COLOUR 6.8 CALL DISTANCE 6.9 CALL PAUSE 6.10 CALL COLOURRESET 6.11 CALL MOVEBACK 6.12 CALL PIXELCOLOUR 7: Miscellaneous Gamebasic Features. 7.1 gb.screen 7.2 gb.slowdown 7.3 Key repeatamatic rate 7.4 Split-screen feature 7.5 Basic TIMER APPENDIX A: INKEY VALUES APPENDIX B: GAMEBASIC ROUTINES SUMMARY APPENDIX C: QBASIC PF KEYS ************************** 1. Welcome to GameBasic. ************************** ________________________ 1.1 What is GameBasic? ________________________ GameBasic is a program which enables students to create their own exciting animated computer games incorporating both sound and colour, using very simple commands in Basic. The objective of GameBasic is to make it FUN to learn computers and Basic programming, to de-mystify computers and to provide a platform which will encourage an enthusiasm for further computer studies, in this way preparing the student for the new work-place in which computer knowledge is essential. With GameBasic, students can develop their own versions of games like Space nvaders, HackMan, Racquet-ball, Question and Answer games with animation, and two-player keyboard games like Tank Battle. Examples of these games written in GameBasic are provided on the program disk (see Program GBDEMO.BAS). This User Guide uses simple language to explain to students the basic issues of PC file structures, the QBasic programming environment, Basic programming, Programming 'Style' and how to use the GameBasic routines to develop their own games. The manual is supported throughout by Basic program examples and the development of one of the demo games is explained step-by-step with program examples. __________________________ 1.2 System Requirements. __________________________ To run GameBasic you must have the following: a) QBasic (QBasic comes with DOS versions 5 and higher and will be ound in your DOS directory). b) a 386 computer or better. GameBasic will run on 286 computers, but your games will be faster if you run GameBasic on a 386 machine or better. c) VGA monitor d) Hard disk drive with 2.0 megabytes of free space. __________________________ 1.3. Installing GameBasic. __________________________ 1. Copy all the files contained in this demonstration version of GameBasic into a new directory (eg: C:\GAMEBASI ) 2. After you have copied the files, to start QBasic make sure that your DOS Prompt is pointing to the directory containing the installed GameBasic files, then type QBASIC and press ENTER. 3. Once you have QBasic started, press the keys ALT then F then alphabetic O to bring up the open-files menu, use the Tab key to move the highlight bar into the files window, then use the direction keys (<- -> etc) to highlight file GBDEMO.BAS then press the enter key. After the demo program has loaded, press F5 to run it. What you will see are a collection of games that have been written in GameBasic to demonstrate its power and ease-of-use. NOTE: If you are running the demonstration version of GameBasic, run program GBDEMO.EXE from the DOS prompt to play the demonstration games. Code for these games is provided in file GBCODE.TXT. NOTE: Just in case GameBasic files become corrupted, you should make one copy of the files you received and store it in a safe place. You can then use this copy to re-install GameBasic if the original disk is un-useable for any reason. ___________________________________________ 1.4 How do you make games with GameBasic? ___________________________________________ 1. Have you ever heard of the word "SPRITE"? The dictionary says that a SPRITE is an elf, pixie, fairy or goblin. It could even be called a SPIRIT - an image that mysteriously appears, moves around, and then disappears, just like a ghost. Scary stuff! In computer-talk, we use the word SPRITE to mean exactly the same thing - an image or character that we show on the computer screen, make it move around and then, maybe, make it disappear. The only difference is that in computers, Sprites are not mysterious - they're controlled by a program. A program that you will be writing very soon using GameBasic! 2. GameBasic makes it very easy for you to create your own special multi- coloured characters. For each character you want to create, you just fill-out a grid of 16 horizontal dots by 12 vertical dots (a block of 16 x 12) and tell the computer which colour you want each dot to be shown as. The combination of all the dots make up your special character. 3. The following is an example of how you would define a Cannon character in GameBasic (actually, this is the Cannon definition that is used in the ALIEN INVADERS game in GBDEMO.BAS): char$(1, 1) = " " char$(1, 2) = " " char$(1, 3) = " char$(1, 4) = " " char$(1, 5) = " 7 " char$(1, 6) = " 7 " char$(1, 7) = " 373 " char$(1, 8) = " 33333333333333 " char$(1, 9) = "33 3 3 3 3 3 33" char$(1,10) = "3333333333333333" char$(1,11) = " 6 6 6 6 " char$(1,12) = " 6 6 " 4. Now, just look at all the "3"'s. The number 3 represents the colour cyan (a kind of light bluey-green); number 7 is white and 6 is brown. Since the screen background will be black, all the spaces you see here will show up as black. What you will see when the Sprite is displayed will be the cyan body of the Cannon, the white barrel (pointing up) and the brown wheels. So you can see how easy it is to create your own special characters in GameBasic. 5. In GameBasic, you might create a Spaceship character, a scary Alien character or even a big green monster - you can create up to 20 different characters to be used in your program in GameBasic. One character might be an evil invading Space Alien, dropping down from the skies to gobble-up your town! Each character you create has to be given a character number - so let's call this Alien Character Number 1. Now, in your program you want to have not one Alien dropping from the skies, but 30 in 3 rows of 10. Each Alien you create to appear on the screen would use the same Character Number (in this case, character 1) but would be identified as a unique Sprite Number. In GameBasic, you can have up to 90 different sprites in each game. In our demo program, we create 30 Aliens with Sprite Numbers from 10 to 39 (yes, that does equal 30!) but each Sprite uses character Number 1 for it's definition, so they all appear the same. 6. At the top of your program you will use the GameBasic DEFINECHAR command to define all your special characters. You will then use other GameBasic commands to control what happens in your program. These commands are very powerful, and save you a lot of time in programming thus making your program much faster to write and much easier to understand and change since there will be very few Basic statements in it. 7. The next command after DEFINECHAR that you're likely to use is the CREATE command. This command assigns a "sprite number" to the sprite, tells GameBasic which special character to display the sprite as, and puts it on the screen at the row and column you specify. The CREATE command also tells GameBasic what speed and in which direction the sprite should move, as well as what to do with the Sprite when it hits a screen border - ie the top,bottom or either side of the screen. When it hits a screen border, you have the following options: 7.1 Sometimes, you might want to have the Sprite wrap-around the screen. This means that when the Sprite gets to one of the edges, it re-appears on the opposite edge. In other words, if the Alien has got to the left edge of the screen, it would re-appear on the right edge if we had said Wrap. 7.2 Another option is to delete the Sprite. This is useful where we have fired a missile, for example, and it has reached the top of the screen without hitting any of those pesky Aliens. 7.3 Yet another option is to leave the Sprite at the edge of the screen. This is useful where the Sprite is one that is controlled by the keyboard (more about this later) such as a Cannon. Here, we don't want the Cannon to get deleted when it reaches the edge, nor do we want it to wrap-around the screen - we want it to stay where it is until the player moves it back. 7.4 A final option is to make the Sprite "Bounce" off the sides, top or bottom, just like a ball. 8. You use GameBasic's CONTROL command to define which Sprite number should be controlled by the keyboard, whether it can move up, down, left or right, which keys will move it in a particular direction and, when a "Fire" key is pressed, what character should be fired (maybe a missile you've defined) and in which direction. This is a very powerful command, saving you a lot of programming time. 9. GameBasic's CHECKHIT command is used to check if one Sprite has hit another one, or one of a range of Sprites. For example, one CHECKHIT instruction could be used to see if a Missile sprite has hit any of our 30 invading Aliens! If it had hit one, then our program could be coded such that the Alien disintegrates or even changes colour.... 10. Finally, one really useful GameBasic command is the SHOOT command. Using SHOOT, your program can literally shoot a specific Character from one Sprite to another Sprite at a given speed. This is used in some of the demonstration games where the Aliens are firing FireBalls directly at the Cannon - they seem to know where the Cannon is every time! This is done with the SHOOT command. GameBasic handles all the angle calculations for you, so you don't have to worry about complicated programming stuff. 11. The exciting feature of GameBasic is that once you've defined all your special characters and you've told GameBasic where to put the characters on the computer screen, in which direction they should move and how fast, GAMEBASIC WILL DO ALL THE MOVEMENT FOR YOU. You don't have to worry about all the complicated programming involved in moving Sprites - you can concentrate on making a computer game that your friends will be amazed at! Maybe you'll beat them this time? 12. This is just a short explanation of some of the routines included in GameBasic - these and all the other GameBasic subroutines are fully explained in Chapters 5 and 6 - GameBasic Commands. I'm sure you can see that with the power of the routines that have been created in GameBasic, you will be able to develop very sophisticated computer games with as little programming as necessary. __________________________ 2. FILES AND DIRECTORIES __________________________ 1. Before we start to explain the QBasic Programming Environment in detail, which I know you're eager to learn, we have to take some time to discuss some general computer issues. 2. Computers process data! Data can mean files of PROGRAM INSTRUCTIONS, which tell the computer exactly what to do, or files of INFORMATION like "Customer Names and Addresses" or "Highest Scores" in a Computer Game on which the programs act. The term FILE means a collection of similar information, like a file of Employee Names or a file of Baseball Cards. We choose a name for each file we create in our computer; the name can be up to 8 characters long and usually has a dot followed by three characters added to the end. For example, BASEBALL.DAT would be a valid file name and might contain information on each of the cards in a BaseBall Collection such as Player's Name, Team, Year, Date Bought, Price, Home Runs etc.... Many of the files in a computer system, however, are program files which already have a name and came with the Program that was installed. Normally, these files contain funny characters that don't make any sense (if you were to look at them) - however, our computer understands them because they contain coded program instructions. 3. Files in a computer are normally stored on a disk. Each disk drive is given a drive letter from A to Z so we can tell the computer which disk drive we want it to read or write. There can be a number of different disk drives in a computer. Just take a look at your computer now. You may see a slot where a large 5 1/2" floppy disk goes - this is probably called your "A" DRIVE. If you also have a smaller disk drive that takes the 3 1/2" disks, it's probably called your "B" DRIVE. But there is one more disk drive that you can't see, although you can probably see its light come on when it's being read or written - this is your computer's internal or hard drive (since its not a floppy). It is larger than either of the two floppy drives and can hold a lot more information on it. This internal hard drive is normally called your "C" drive, but hard drives can also have other drive letters like "D", "E" etc... All this means is that the large hard disk inside your computer has been sub-divided into smaller drives. It hasn't been physically cut up; just imaginary - like drawing lines on a sheet of paper and labelling the areas "C", "D" etc.... 4. So why all this talk about disk drives? Well, computer files are not only assigned a name, but they are also assigned to a disk drive by putting the drive letter and a colon in front of the file name. If our BASEBALL.DAT file was on our "C" internal hard drive, we could refer to it with the name C:BASEBALL.DAT this would tell DOS (the operating system that handles all our file and program processing) that the file can be found on the "C" internal hard disk drive with the name BASEBALL.DAT 5. Now, if all our different programs that we have in our computer were on the same disk drive, we'd have quite a mess. There would be no easy way to tell which files belong to our Game, which files belong to the program which does Dad's Tax Return, which files belong to Mum's CookBook Card system and so on. They'd all be jumbled up together - a real mess. 6. To get over this problem, we store all files for a specific program in their own DIRECTORY, to which we give a a label saying COOKBOOK RECIPES, another file folder might have a label saying BASEBALL CARDS and so on. Now in our computer we could keep all Mum's recipes in the COOKBOOK file-folder, and all our BASEBALL Cards in the BASEBALL file folder. This keeps all similar files together, and stops them getting mixed up (just in case Mum might confuse one of our Baseball cards with one of her recipes). Both these file folders (or DIRECTORIES) could be on the same disk drive. We can picture this as follows: DISK DRIVE C _________|_______ | | | | | | BBALL CBOOK <-----DIRECTORIES | | | | baseball.dat recipes.doc<-----FILES baseball.prg cookbk.prg etc.. etc.. 7. When we want to tell DOS (our computer's operating system) where our BASEBALL.DAT file is, we have to tell DOS that it's in the BBALL directory under the name of BASEBALL.DAT. The character string C:\BBALL\BASEBALL.DAT does this. NOTE that it doesn't make any difference if you type your file or directory names in capital letters or small letters - they're both the same as far as DOS is concerned. ____________________________________ 3. QBASIC PROGRAMMING ENVIRONMENT ____________________________________ 3.1 Introduction _________________ What is the QBasic Programming environment, and why do you have to learn it first? When you program in QBasic, you will be creating a file containing Basic Program instructions that tell the computer exactly what to do. This file will contain a number of lines, depending upon the size of your program. When you tell Basic to RUN your program, it will process each line in your program in sequence until it gets to the end or an instruction that says END or STOP. The QBasic Programming Environment is a collection of screens that let you create, change and run your Basic Programs. Using this environment, you can create a new Basic program, save a program to disk giving it it's own name, change a program you previously created, run programs, print out your program listings and so on. 3.2 Starting QBasic. _____________________ 1. In the previous chapter we discussed FILES and DIRECTORIES. What does all this have to do with learning the QBasic Programming Environment? Well, the first thing you're going to have to do NOW is to start-up the program that runs this QBasic Programming Environment. This is called QBASIC.EXE and should be found on the disk drive and in the directory containing your DOS operating system (probably C:\DOS ). If you're not sure where this drive and directory is, you may need to ask your parent or a computer-knowledgeable person. 2. After you've turned the computer on, it will start loading in its operating system from the hard drive and then display what we call the DOS PROMPT. This will normally look like "C:\>_" or "C:\DOS>_" The underscore character will be flashing. This is the "Cursor" position, where anything you enter from the keyboard will be displayed on the screen. 3. Now you have to change the DOS Prompt to point to the directory where you installed the GameBasic files that came on the Program disk. First, if the drive containing your installed GameBasic files is not the same as the drive your DOS prompt is currently pointing to (ie the C in C:\DOS ), then you will have to change the drive. Do this by typing "x:", without the quotes, where x is the letter of the drive containing your installed GameBasic files. Having done the above, if you needed to, now type "CD \ xxxxxxxx", again without the quotes, where xxxxxxxx is the directory name that contains your GameBasic files, and press the Enter key. Finally, to start the QBasic program, type QBASIC and press enter. If you get an error message during the above, then either a) You typed in a wrong directory name or character (redo from the start) or b) Your DOS directory is not included in your AUTOEXEC.BAT file's PATH statement. (You'll have to get someone to add it for you) or c) You don't have the QBASIC.EXE program on your computer. (you will not be able to run GameBasic without QBASIC.EXE) 4. After the computer loads the QBASIC program into its memory, you should see the following on your screen. _________________________________________________________________ | File Edit View Search Run Debug Options Help | |_________________________________Untitled______________________| | | | | | | | | | ________________________________________ | | | | | | | Welcome to MS-DOS QBasic | | | | | | | |Copyright (C) Microsoft Corporation | | | | All rights reserved. | | | | | | | |< Press Enter to see the Survival Guide >| | | _________________________________________ | | | |< Press ESC to clear this dialog box > | | | |_________________________________________| | | | |_______________________________________________________________| YOU ARE NOW IN QBASIC - CONGRATULATIONS! _________________________________________________ 3.3 The QBasic Programming Environment- a Tour. _________________________________________________ HINT: IF AT ANY TIME WHILE IN THE QBASIC ENVIRONMENT YOU FIND THAT THE COMPUTER DOESN'T SEEM TO BE RESPONDING TO THE KEYBOARD, PRESS THE ESCAPE KEY A COUPLE OF TIMES TO RESET THE COMMAND BAR AT THE TOP. First, press the Esc key to clear the dialog box. Now, look at the top of the screen. You'll see eight commands; File, Edit, View, Search, Run, Debug, Options and Help. By pressing the Alt key followed by the first character of an Option (for example, Alt and F for the File option) each of the options brings-up a menu of actions that you can chose from. Once a menu is displayed, you can use the direction keys (<- -> etc) to move the highlight bar to the action you want to take. Try it now. Press Alt and F. You should now see a menu below the File Option that looks like the following: ________________________________________________________________ | File Edit View Search Run Debug Options Help| | | |____________________________Untitled___________________________| | | New | | | | Open... | | | | Save | | | | Save As.. | | | |___________| | | | Print. . | | | |___________| | | | Exit | | | |___________| | | | | | | | | | | | | | | | | | |_______________________________________________________________| From this menu of choices, you can tell QBasic that you want to create a "N"ew program, "O"pen an existing Basic program, etc.... All you need to do when you see the choices to select an action is to press the capitalised letter of your choice. We'll now take each option one at a time. 3.3.1. FILE - OPEN option. _____________________________ With the File menu bar displayed, (ALT followed by F) press the key for the letter O. You will now see a window appear that shows you all the Basic program files that are stored in the directory that is shown just below File Name (for example, C:\GAMEBASE) _________________________________________________________________ | File Edit View Search Run Debug Options Help| |____________________________Untitled___________________________| | ___________________________ Open ___________________________| | | _____________________________________________ | | | File Name: |*.BAS | | | | |_____________________________________________| | | | C:\GAMEBASE | | | Files Dirs/Drives | | | _____________________________________ _____________ | | | | BAS01.BAS BAS09.BAS GAME02.BAS | | .. | | | | | BAS02.BAS BAS10.BAS GAME03.BAS| |[-A-] | | | | | BAS03.BAS BAS11.BAS GAME04.BAS| |[-B-] | | | | | BAS04.BAS BAS12.BAS GAME05.BAS| |[-C-] | | | | | BAS05.BAS BAS13.BAS GAME06.BAS| | . | | | | | BAS06.BAS BAS14.BAS GAME07.BAS| | . | | | | | BAS07.BAS GBBASE.BAS GAME08.BAS| | . | | | | | BAS08.BAS GAME01.BAS GAME09.BAS| | | | | | |_____________________________________| |_____________| | | _____________________________________________________________| | | | | |_______________________________________________________________| To select a program file so that you can change it, press the Tab key to get the flashing cursor into the FILES area of the window (The Tab key looks like -->| ). Once the cursor is in this area, press the direction keys to move the highlighted area to the program file you want. For this example, move it so that it highlights the file named BAS01.BAS. Now press the Enter key. Demo program BAS01.BAS QBasic will now go and read that file off the disk and display the program code in an edit window. You can now change the program; the next section will explain exactly how you do that. __________________________________ 3.3.2. EDITING A BASIC PROGRAM. __________________________________ Now that you have a basic program displayed in the edit window, you can move the cursor up, down, left and right (using the direction keys) to the place in the program where you want to make a change. Notice, as you do this, that the lines in your program scroll up and down when you go past the top or bottom of the screen. You can also use the Page Up and Page Down keys to move up and down in your program page by page. The Home and End keys take you to the beginning or end of the program line your cursor is on currently. Now, a word about the QBasic editor and program commands. Until you have an understanding of what the QBasic programming commands are, you'll find it difficult to make changes to a QBasic program file since QBasic has a "Smart" editor. This means that each time you make a change to a program line, if QBasic doesn't understand what you've entered (ie it is not a valid program instruction) it will display an error message. For this reason, the file BAS01 contains only Comment records (ie records that have either the three letters REM (which stands for Remarks) or a single quote ( ' ) at the beginning of the line). To QBasic, all the text following a single quote (or REM) is comments, not program instruction, so you won't get an error message when you change any of these lines (as long as you don't delete the REM or quote at the beginning of the line) 3.3.2.1 ENTERING TEXT WITH INSERT ON and INSERT OFF _____________________________________________________ OK, so now try and change some of the program lines in BAS01.BAS Move the cursor to between the "IS" and "COMMENT" words and type HELLO. See how the text HELLO is added to the line, and all the text after the place where you inserted HELLO is moved along! This is INSERT mode. Now, position the cursor to the character immediately after the O in HELLO. Press the Enter key. Did you see how the text after the cursor gets dropped down to a new line! Now, if you type any characters into the line that got dropped down and move the cursor up to the previous line again you'll get an error message, since QBasic is saying that it doesn't understand the command on the line that you just created (the line doesn't start with REM or a quote, so it's NOT a comment line now and QBasic thinks its a program command line). Press the Enter key to get back to the program and now move the cursor back to the position immediately after the O in HELLO again. Now press the Delete key. The previous line should now have been moved back to where the cursor is. Now press the Insert key. This turns INSERT mode off. Now go through the same steps again and watch the differences. This is TYPEOVER mode - what you key in types over what is under the cursor position; it doesn't move the following text along. You can tell that you're in INSERT mode by the shape of the cursor - the white line or box that is blinking on the screen. In INSERT mode the cursor is a white blinking underline; in type-over mode it's a large blinking white box. Got the idea? If so, let's move on. 3.3.2.2 CREATING BLANK PROGRAM LINES. _______________________________________ You currently have INSERT mode turned off. Press the Insert key again which will turn Insert mode ON again. Note that the INSERT key acts as a "toggle", flipping between INSERT ON and INSERT OFF each time it is pressed. Now move the cursor to the beginning of a line and press Enter. The line will move down and a blank line will be shown where the cursor was. Keep pressing the Enter key, and you get more blank lines. You can move the cursor up now and enter new Basic commands in the blank lines you've just created (remember to make the first characters either a quote ( ' ) or REM, otherwise you'll get an error message again). 3.3.2.3 DELETING CHARACTERS or WHOLE LINES IN ONE STROKE. ___________________________________________________________ You can delete characters to the right of the cursor by pressing the DELETE key. You can also delete complete lines. To do this, move the cursor to any program line. Now hold down the Ctrl key and press the Y key at the same time. Watch the line where the cursor is on get deleted and all following lines move up. This is one way you can delete program lines you don't want any more. 3.3.2.4 MOVING/COPYING/DELETING BLOCKS OF LINES. Quite often, you will have entered a number of program lines somewhere in your program and later on, you'll want to delete them or copy/move them to another place in your program. This is how you do it. (You'll have to pay attention - this is a little bit more difficult.) A) First, move the cursor to the first line you want to copy, move or delete. Now, hold down the Shift key and, while the Shift key is being pressed, move the cursor down to the last line you want. (You can use the Page Down/Up and arrow Direction keys to do this). Selected text will be highlighted. B) Once you have selected all the text you want, release the Shift key. C) Now, if you want to move the program code from where it is and place it in a new location, (cut and paste); Holding the Shift key down, press the Delete key to cut the program lines from their current location (you will see them disappear), then move the cursor to where you want to re-position the lines and, holding the Shift key down, press the Insert key to paste the lines in the new position. D) If you want to leave the program lines where they are but make a copy of them at another location: Holding the CTRL key down, press the Insert key to place a copy of the program lines into memory, then move the cursor to the place where you want to copy the lines and, holding the Shift key down, press the Insert key to copy the lines to the new location. You can add additional copies of the lines in new locations by moving the cursor to where you want the lines and pressing the Shift/Insert keys again. E) If you want to Delete the highlighted lines, simply press the Delete key. Practice this on program BAS01.BAS. It will save you a lot of time later on when you are editing your programs. 3.3.3. FILE - SAVE AS Option. ____________________________ As a safety feature, all GameBasic programs supplied on the program disk have been installed in your directory as READ-ONLY. This means that you can't make any changes to them. As you go through this User Guide you will be told to retrieve these programs. It is suggested that immediately after retrieving a program, you save it under a different name - use the existing program name and add your initials to the end (for example, BAS01XX.BAS) where XX would be your initials. Once you have done this, then you can use your saved version to make changes. Here is how you save a program under a different name: Use the SAVE AS option under the File menu (ALT + F + A). In the File Name box, enter the new name for the program and press the Enter key. When you save a program under a different name, Basic doesn't re-name the existing program; it makes a copy of the program, so your original program will still be there under its original name. You will use the SAVE AS feature other times in your program development. When you first start programming a new game, you will have to retrieve the GameBasic Base program GBASE.BAS and save it with the name you want to give to your new game. As you develop your game, you should save the program as a different name each time you get new features working in your game and before you start developing new features. Then, if you "screw-up" something (a technical term!) you can always go back to the previous version that worked. It is suggested that you restrict your game's name to 6 characters, then you can add a two digit version number to the end (for example, ALIEN01.BAS, ALIEN02.BAS etc..) 3.3.4. FILE - SAVE Option. ____________________________ Once you are happy with the changes you have made to your program, you would normally RUN the program to see if it gives you the results you wanted. If it did, then you would SAVE the program for future use. But for now, we'll bypass the RUN command and just SAVE the changes that we've made (assuming you made a copy of program BAS01.BAS and added your initials to the end as suggested in the previous section, and that that is the program that you're now working with). If you are still working with the original BAS01.BAS, you won't be able to save any changes to it. To save your program, press the Alt, F, and S keys in turn. As you press the keys, watch the top of the screen. You'll notice that the Alt key highlights the choices bar. The F key pulls down the Files menu and the S key selects the SAVE option. HINT: As you key in a new program, or make extensive changes to an existing program, save the program after one or two screens of input as a safety measure, just in case you lose power before completing your input or your system "hangs-up" (yet another technical term that relates to when your computer simply "freezes" - accepting no input from the keyboard). 3.3.5 FILE - NEW Option. ______________________________ When the File menu is displayed and you press the letter N (for New), QBasic will set up a blank edit screen into which you can start keying in Basic instructions for a new program. When you have entered an instruction for one line, press the Enter key and the cursor will jump to the start of the next line. Any corrections or additions you want to make as you are entering commands are done exactly the same way as described above. However, there is one difference between entering a new program and editing an existing program. When you have completed keying in your program and go to save it (Alt, F, S), QBasic will ask you what name you want to give your program. You've just written a new program, so QBasic doesn't know what name to call it when you tell it to save the program. In the window that pops up asking for the program name, simply key in up to 8 characters for the program name. You can key in less than 8 characters, but no more than 8. The name should normally contain only alphabetic and numeric characters. It is best to name a program for it's purpose so you can easily identify it later when you're trying to find it among a list of programs. In other words, ALIENINV is a better name for a game program than XPROG12. QBasic automatically gives your file the extension of .BAS so if you looked at a list of files in the directory you're currently in, you would see your program saved as (for example) ALIENINV.BAS 3.3.6 RUN - START option. _____________________________ Let's run a real program now! (I can hear you saying that it's about time). Demo Program BAS02A.BAS We're going to get a program called BAS02A into the Edit area then run it. First, press Alt, then F then O to select the File - Open option. When the program selection screen comes up, move the cursor to the Files area (use the Tab key; - >| ) and use the direction keys to highlight program BAS02A.BAS Now press the Enter key. BAS02A will be read from the disk and placed in the Edit area of QBasic. Here is the program: CLS PRINT "Hi there! So this is your first Basic program?" END Can you make out what its going to do? If not, don't worry, we'll explain everything about Basic commands in the next chapter. Let's run this program ! Press Alt, then R then S to select the Run - Start option. The screen will now go black, and you'll see a message printed in white at the top and a line that says "Press any key to continue" at the bottom. Our program has just run and come to the end. It was a very simple program that just displayed a message to the screen - but it WAS a program, even though it only had three lines. Now, press any key. You will be passed back to the QBasic Program Edit screen, with the BAS02A program showing again. Change the text in the program between the quotes. Now press Alt, R and S again. See how the message at the top of the screen has changed! You've just made your first program change. Congratulations! 3.3.7 EXITING QBASIC. _________________________ To get out of QBasic and return to the DOS Prompt, press ALT + F + X (eXit). If you have any unsaved program changes outstanding, you will be asked by Basic if you want to save the program before exiting. 3.4 OTHER QBASIC OPTIONS/QBASIC HELP _____________________________________ Before we finish our Tour of QBasic Programming environment, you should notice that there are a number of other options that can be selected from the top menu. To get an idea of what they do and how to use them, please refer to the Basic Help Option. You access this by pressing Alt, H and then selecting one of the options presented. The documentation you will find in Basic's Help is very comprehensive. ______________________________ 4. LEARNING BASIC PROGRAMMING. ______________________________ Don't listen to what other people tell you; programming is not that difficult. Some people will tell you that you have to be an expert at mathematics to be a programmer - that's not true! You can be the class- dummy in mathematics and still be an expert programmer - this author is an example. However, you do have to think in a logical way because the computer follows your instructions "to the letter". If you told it to jump in the river (if computer's could do that), it would! 4.1 FLOWCHARTING. __________________ Now, what do we mean by "think in a logical way"? The computer performs mathematical calculations and tests on numbers and makes decisions based on the results. That's all it really does. The actions it is told to perform based on the tests it does make up your program. We make decisions and take action on those decisions every day of our lives. Let's take an example. Suppose you were to draw out the decisions and actions you make when you get up in the morning. First, you'd get up and get dressed then, if you were hungry and there was food in the house, you'd have breakfast. Finally, you'd leave the house for school or the office, taking your rain-coat if it was raining. (Having a shower and brushing your teeth are optional today!) If we were to draw out the decisions and actions that you go through in what programmers call a flow-chart, it might look something like the following: Action: Get up. Action: Get dressed V | Yes Decision: Am I hungry? -----> | | No | V Yes V Decision: Food in the house?----------> | | | | No | | | V V | Action: Drink water Action:HaveBreakfast | | | | V V |---------------------<-----------------------<- V | Yes Decision: Is It Raining? -------> | | No| | V Action: Take Raincoat | | |---------<-------------------- | Action: Leave House. Note that there can only be two outcomes from a decision or test - either the condition is TRUE (it IS raining) or it's FALSE (it's NOT raining). The decisions and actions in all computer programs can be drawn in flow-chart diagrams similar to the one above. This is a very good thing to do before you start entering your program instructions into the computer - it gives you a high-level diagram of what your program will do, so you can check the logic for "logical" problems before you enter any code (Programmers refer to program instructions as "code"). As an example, you might have written "Is it sunny?" instead of "Is it raining". Obviously, the action "Take Raincoat" is not appropriate if the answer to "Is it sunny?" is YES. This is a logic error. Also, if you had said "Flush toilet" instead of "Take Raincoat", this would probably be another logic error, unless there was a very good reason you wanted to flush the toilet every time it rained! As you write more programs, you'll find that you make quite a few of these types of errors - your program will give you some very funny results and you'll say "How could it be doing that?" and eventually you'll trace the problem down to a silly little error like one of the errors above, so it is strongly recommended that you write a flow-chart of what your program will be doing before you even start-up your computer. 4.2 VARIABLES IN BASIC. ________________________ Having said this, we should now explain what a computer program works with. A program performs operations on numbers and letters, that's all. The data it works with (the numbers and letters) are stored in separate areas inside the computer's memory. These areas are called VARIABLES, and you give each variable its own unique name. In Basic, variables can have up to 40 characters and numbers in their name. They must start with an alphabetic character and cannot have any spaces anywhere in the middle of the name or any special characters like * - ( @ and so on. Alphabetic characters used in variable names can be either upper- case (capital letters) or lower-case (small letters). 4.2.1 NUMERIC VARIABLES ___________________________ Again, let's take an example. Imagine that the two figures we've drawn below are buckets; one we've called bucket A and the other bucket B. ------ | | | | | | | | | | V | | | A = 45 | | | | | 45 | | 0 | _______ _________ A B The computer instruction A = 45 will put the value of 45 into bucket A. (think of this instruction as saying "set A to the value of 45"). Bucket B has zero in it. -------------------------- | | | | | | | | | | | | V | B = 66 | | | | | 45 | | 66 | _______ _________ A B Now, if we were to say B = 66 , (set bucket B equal to 66) then bucket A would still contain the value 45, but now bucket B would not have zero; it would have 66 in it. If you were to look into bucket B and open it up, you'd find number 66 lying at the bottom. (That's meant to be a joke!) So now we have bucket A with 45 in it and bucket B with 66 in it instead of zero. ------------------- | | | | | | | | | | | | V | | | | | | 45 | | 45 | _______ _________ A B Now, if we were to write the instruction B = A, (set bucket B equal to the value of bucket A), what do you think would be in bucket B after the computer executes the command? (Remember that when we said B = 66, the computer moved the value of 66 into bucket B). Yes, Bucket B would contain 45, since you're telling the computer to take the value laying in bucket A and move it to bucket B. Whatever was in bucket B before this command was executed (the value of 66 in this example) would be lost forever, gone for good, vanished away etc... (get the idea?). However, when we moved the value of bucket A into bucket B, we didn't wipe it out of bucket A. Bucket A still contains 45 - the same as bucket B now. In other words, after this command has executed, bucket B is the same as (or equals) bucket A. Now, whenever your program uses bucket B, it would have the value of 45 until a subsequent command in your program again changed the contents of bucket B. If we now said B = (A + 30) * 2 , what do you think would be stored in bucket B after this command executes? (The asterisk means Multiply). The answer is 150 since the computer would look into bucket A and get the value of 45, then it would add 30 to it to give 75, then multiply this last number by 2 to give 150. So you see how the computer works. It stores its numbers in buckets. Then, when a command uses that bucket, it goes and extracts the number that's kept in the bucket and uses it in the calculation. Pretty neat, huh? Finally, instead of calling the place where the computer stores each number as a "bucket", let's call it a "variable". Why the word VARIABLE? Well, it's because the value that is stored in it can change from one command to the next as the program is running. In other words, its contents are variable. Whenever computer books talk about variables, they're simply talking about these buckets where we keep values. As was mentioned above, we give our variables unique names so we can tell the type of information we are storing in them. This is quite handy, and helps us to read and understand what our program is doing. Make your variable names meaningful so that when you read through your program, you understand how each variable is being used. As an example, if we were to set up a variable to hold a score in a computer game, we'd probably call the variable "score". Too short a name (for example, "sc") would not be very descriptive, and too long a name (even though you can have up to 40 characters in your variables name) would be too much typing each time you wanted to refer to the variable in your program (ie "accumulated.score.this.game" ) as well as being very error- prone (more about variable name errors in a minute). Let's take an example to show what we've discussed above. Retrieve program BAS02.BAS now (Alt + F + O then highlight BAS02.BAS and hit enter). The code (program instructions) looks like the following: CLS score = 0 points.per.hit = 100 ' print line 1 PRINT "Score = "; score 'print line 2 score = points.per.hit PRINT "Score now equals "; score 'print line 3 score = score + points.per.hit PRINT "Score has been incremented to "; score 'print line 4 score = score + (points.per.hit * 2) PRINT "Score is now "; score END Run the program and see what it prints out on the screen. (Basic runs your program by starting at the top and executing each instruction in sequence until it gets to an END or STOP instruction). When the program gets to the first PRINT instruction, the value of the variable (bucket) called 'score' is zero (that's what we set it to at the top of the program). The first printed line will say Score = 0 Next, we set the variable named score equal to the value contained in variable points.per.hit (which is 100), so the next print line will say Score now equals 100 The next instruction takes the value that is currently in the variable (bucket) called score (which is 100), adds the value that's currently in the variable named points.per.hit (which is 100 also) and places the result of the addition (200) back in the variable named score, so the next print line says Score has been incremented to 200 Finally, the next instruction multiplies the value currently in points.per.hit by 2, adds the result of this multiplication (which is 100 * 2 = 200) to the value currently in the variable called score (which is 200) and places the result of this whole calculation back in the variable score. So the last print line will say Score is now 400 Get the idea? Try making some changes to the calculations and see the different results you get! HINT: WHEN YOU'RE TYPING IN YOUR PROGRAM INSTRUCTIONS, BE VERY CAREFUL TO MAKE SURE THAT YOU SPELL YOUR VARIABLE NAMES CONSISTENTLY. Let's look at one type of error that can be made with mis-spelled variable names. Change the second PRINT line in program BAS02.BAS that says PRINT "Score now equals "; score to say PRINT "Score now equals "; scire Run the program again. On the second line it prints out, it will now print Score now equals 0 We deliberately mis-spelled the variable "score" above as "scire". When the basic program comes to execute this program ine, it won't know that you really meant to type "score" . Since asic hasn't come across the variable "scire" before it gets to is print line, it will assume that "scire" is a new variable and set t up with a value of zero (the initial value for numeric ariables). Instead of the program printing Score now equals 100 it will print Score now equals 0 Sometimes the error you have made in a variable's name is not obvious and doesn't come springing out at you, especially hen there is a lot of program code between the place where the rror was made and the last place the variable was correctly amed. ou can waste quite a lot of time tracking down a spelling error - so TAKE CARE! 4.2.2 USING VARIABLES IN CALCULATIONS. __________________________________________ In Basic, you can perform any arithmetic calculation using any number of variables. The operations you can perform include addition (+), subtraction (-), division (/) and multiplication (*). Note that multiplication uses the * character rather than the normal X (since X is an alphabetic character and could be mistaken by Basic for a variable name). Calculations should be bracketed for clarity - the number of left and right brackets have to be equal. There are correctly formatted calculations (although they're not very descriptive variable names): abc = ( (aa + bb) * gg ) / xx x = y * (a - b) / 100.34 This next line would be invalid because there is one more left-bracket than right brackets: x = ( (d - 40) * 2.67 So now you know you that the computer stores numbers in buckets which we call "variables" and we give them names to refer to them by, so let's move on shall we? 4.2.3 ALPHABETIC VARIABLES ______________________________ There's one other type of information that computers store as well. Can you guess what it is? The answer is Alphabetic information or text , like your name or your address. This type of information is not like numeric information because you can't do mathematical calculations on it, but it does get stored in the computer's memory in nearly the same way. If we wanted to store your name in a text variable (which is called a STRING variable in Basic because it's a string of characters), we would say Name$ = "John Doe" There are two differences between this string variable and a numeric variable (like A = 30). First, the variable name has a $ (dollar sign) after it. Think of this sign as an S (for STRING) with a line through it rather than a dollar sign. Basic stores string information in a different way internally than it stores numeric information - the $ sign tells Basic that the variable is a string variable and will hold alphabetic characters rather than a number. Secondly, the value we want to store in this variable is enclosed in quotes. If we left the quotes off, Basic would get confused and think that John and Doe are the names of numeric variables. So remember: for string variables - dollar sign at the end of the variable name and quotes around the value. One last word about string variables. You'll remember that we said that you can't do arithmetic on string variables - well that's not quite true; you can add them together. Demo Program BAS03.BAS Load program BAS03.BAS and look at it. This is a GameBasic program. (All programs starting with BAS or GAME include only those GameBasic routines neccessary to support the example being taught. If you change them to call other GameBasic routines you will get an error. Program GBASE.BAS includes ALL GameBasic routines). You will notice two program lines at the top enclosed between two lines of asterisks. These are GameBasic instructions and must NOT be changed. For the purposes of this example, your program code starts after the line of exclamation points ( !!!! ). Don't get confused by the DO WHILE and LOCATE instructions; we'll cover those in a minute. first.name$ = "John" last.name$ = "Doe" defender.name$ = first.name$ + last.name$ score = 0 points.per.hit = 100 '*******main program loop******** end.of.game$ = "N" DO WHILE end.of.game$ = "N" LOCATE 1,1 PRINT "Defender: "; defender.name$ LOCATE 2,1 PRINT "Score : " ; score . . Look at the third line above. After this line has been executed, what value do you think is now in the variable defender.name$ ? Let's see. The first and second lines define first.name$ and last.name$ variables and store a value in each. The third line adds the two variables together so we would get "JohnDoe" in the variable defender.name$ Run this program now. (ALT then R then S) See how it prints the name and the score at the top of the screen? (DON'T GET TOO ENGROSSED IN THE GAME !! ) If we wanted a space between first and last names, we'd have said defender.name$ = first.name$ + " " + last.name$ The space between the quotes adds the space between first name and last name in the defender.name$ variable. What would happen if we left off the "$" character from the variable last.name$ on line 2? Try it and see. We'd get "Type mismatch" because Basic thinks that last.name is a numeric variable and we're trying to add it to a string (alphabetic) variable - which we can't do! One final word, which applies to both types of variables: YOU HAVE TO DEFINE THE VARIABLE BEFORE YOU USE IT. In other words, you can't say the following: 'start of program comment line PRINT SCORE SCORE = 40 because SCORE has not been defined before the PRINT command executes. (Remember that variable names can be upper and lower case letters!). Basic executes your program commands in sequence from the top to the bottom. When it comes to the PRINT command (in this case the first command) it doesn't know anything about the variable called SCORE, so it will set SCORE up with a value of zero and print zero. Note that in the commands 'start of program comment line points.per.hit = 100 score = points.per.hit score is a valid definition (or first-use) of a variable; it doesn't have to be defined before with a line like "score = 0" NOW WE'VE EXPLAINED HOW NUMERIC AND STRING (ALPHABETIC) VARIABLES (OR BUCKETS) ARE CREATED, NAMED AND USED IN PROGRAMS, WE'RE GOING TO INTRODUCE YOU TO THE MAIN BASIC PROGRAM COMMANDS, ONE BY ONE. FIRST, we'll start with one of the easiest - the CLEAR SCREEN command. 4.3 BASIC COMMAND: CLS (CLEAR SCREEN) _____________________________________________ CLS clears the computer screen of everything currently being displayed and sets the cursor (the flashing underscore that shows you where your next displayed character will be shown) at the top of the screen. This instruction only clears the screen, it DOESN'T clear any memory or re-set any variables. If you had just displayed the contents of variable SCORE and then followed the instruction with a CLS instruction, all your variables (including SCORE) will be exactly as they were just before the CLS instruction was processed by the computer. Pretty easy, huh? Let's move on to the next command; the INPUT command: 4.4 BASIC COMMAND: INPUT "text message" ; variable _________________________________________________________ Sometimes in your program you will want to get information from the user at the keyboard; maybe the screen shows a list of options and you want the player to enter one, or maybe you want the player to enter their name. The command you use is the INPUT command, as follows: INPUT "Enter your name! " ; name$ name$ is a variable name , and it doesn't have to be pre-defined; this may be the first time in your program that this variable has been mentioned. When the computer executes this instruction, it will display the message "Enter your name!" on the next available line of the screen and the cursor will be positioned immediately after the message, waiting for the player (or you!) to input their name. You would then key your name and press the Enter key. The computer would then take the character string you entered (your name) and store it in a variable called name$ (as in our example). You could have called the variable any valid Basic name, such as FNAME$ or last.name$ etc.... Now look at this INPUT command: INPUT "Please enter your age: "; age Because the variable "age" doesn't have a $ sign after it, it is a numeric variable. If you enter any non- numeric key (like "A") the computer will print "REDO FROM START" after you press the enter key - this is telling you that you had an error in the input and must key it in again. For string variables (which have a $ sign after the name), any alphabetic or numeric value can be entered from the keyboard. For either type of variable, you must always press the enter key to tell Basic that you've finished inputting. Demo Program BAS04.BAS Let's change the program we were working with before to ask for the player's name. Retrieve program BAS04.BAS The first four lines at the top have now been changed to INPUT "Enter your first name: "; first.name$ INPUT "Enter your last name: "; last.name$ defender.name$ = first.name$ + " " + last.name$ PRINT "Welcome, " + defender.name$ + ". Press Enter to start." Now run the program and watch what happens! (Alt + R + S) 4.5 BASIC COMMAND: PRINT ________________________________ PRINT is a Basic command that's a throw-back to the days when the only output device to a computer was a teletype or printer. Now, we have video-terminals, but Basic uses the command Print to display information on the screen. It's all very confusing, isn't it! It would have been much easier if they had made a new command that says DISPLAY, but they didn't and we're stuck with PRINT. All we have to remember is that when we issue the Basic command PRINT, we're telling Basic to display what follows the command on the video-screen. So how does this PRINT command work? It's pretty easy. You've already seen some examples in the programs above. The format of the PRINT command is PRINT variable1; variable2; variable3; . . . where variable 1, 2, 3 etc can be a literal string like "ENTER YOUR NAME" or any string variable (for example,first.name$ ) or any numeric variable (for example, AGE) The following is a PRINT instruction used in the program we were just looking at: PRINT "Defender: " ; defender.name$ If we wanted to print score on the same line, we could extend the PRINT command to say: PRINT "Defender: " ; defender.name$ ; " Score: "; score If you don't type the semi-colon (;) between the variables, the Basic smart-editor will put them in for you anyway. You can even do calculations in the PRINT command as the following will demonstrate: CLS Age = 15 PRINT "I am half the age of a "; Age*2;"year old! How old am I?" END 4.6 BASIC COMMAND: LOCATE _______________________________ As each line is printed, the cursor moves down to the next line. When it reaches the bottom, the lines above it scroll upward so that the last line printed is always at the bottom. Sometimes, however, we want to PRINT information at a particular place on the screen. To do this, we have to use the LOCATE command before we use the PRINT command. The video-screen is made up of a number of rows down the screen and a number of columns across the screen. When you're printing information in screen mode 1 in Gamebasic, (more about screen modes a bit later) there are 25 rows and 40 columns. In screen mode 2, there are 30 rows and 80 columns. The format of the LOCATE command is LOCATE row, column As an example, LOCATE 2, 5 would move the cursor to the A in the diagram below. Whatever you then printed, would start from that position on the screen. Column: 1 2 3 4 5 6 7 8 9 10 . . . ---> 40 Row 1 . . . . . . . . . . . . . . . . . 2 . . . . A . . . . . . . . . . . . 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . V . . . . . . . . . . . . . . . . . 25 . . . . . . . . . . . . . . . . . So, LOCATE 2, 5 PRINT "START" would give: Column: 1 2 3 4 5 6 7 8 9 10 . . . ---> 40 Row 1 . . . . . . . . . . . . . . . . . 2 . . . . S T A R T . . . . . . . . 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . V . . . . . . . . . . . . . . . . . 25 . . . . . . . . . . . . . . . . . at the top left of the video screen. That's all you basically need to know about the LOCATE and PRINT commands. 4.7 BASIC COMMAND: IF .... THEN .... ELSE ___________________________________________ Very often in your program you will want to test the values of certain variables and take different action depending upon the outcome. Basic uses the IF.. THEN ... ELSE commands to do this. The format is IF condition.1 THEN action.1 ELSE action.2 As an example: in the program we were just looking at, if we added code to the program to get the player's age and also ask whether they wanted to play a fast or slow game, we could then test the replies and make our program take different actions based on the replies. Demo Program BAS05.BAS Load program BAS05.BAS now and look at the changes. You will see that we've added the following lines to our program at the top: PRINT "What is your age, " + first.name$ + "?" INPUT age INPUT "Do you want to play the slow or fast game(s/f)";game.speed$ game.speed$ = UCASE$(game.speed$) PRINT " " start.speed = 40 IF ( game.speed$ = "S" AND age > 29 ) THEN start.speed = 30 PRINT "Getting too old to play the fast game?" ENDIF IF age < 8 THEN PRINT "You're rather young for this?" IF game.speed$ = "F" THEN PRINT "You better wake up for this one!" ELSE PRINT "OK - so take the easy option" ENDIF PRINT "Good luck, " + first.name$ + "!" PRINT "Press Enter to start" INPUT " ", dum$ Before we explain what this whole block of code is doing, there are a couple of things we should mention. 1. Why did we include the line game.speed$ = UCASE$ ( game.speed$ ) and what is it doing? Well, the keyboard, like a typewriter, has upper-case and lower-case letters. When we ask the player to enter character information which we later want to test to see if it's a certain value, we don't know if they are typing in upper-case or lower case. If we do a test for a lower-case "f" (for example) and they typed an upper-case "F", then the test will fail. In other words, a lower-case "f" is not equal to an upper-case "F". There are a number of "functions" in Basic that perform specific actions on variables. For instance, the SQR function gives the square-root of a number. A = SQR(100) will put the value of 10 into variable A, since 10 is the square root of 100. The UCASE$ function works on a string variable and converts the variable to all upper-case letters. So the command "game.speed$ = UCASE$(game.speed$) " will convert all the characters in the variable game.speed$ to upper-case characters and place the result back in the game.speed$ variable. Now, when we want to test this variable in our program for a specific value, all we have to test for is the upper-case letter, since the variable can NOT have lower-case letters in it after the UCASE$ command. If we didn't do this, then we'd have to say in our IF condition IF game.speed$ = 'f' OR game.speed$ = "F" THEN ..... There are many Basic functions you can use in your programming once you become familiar with Basic. The HELP feature in QBasic (Alt + H) is very comprehensive and will be a good source of information for you. 2. In the Basic language, we don't write "greater than" or "less than" in our IF .. THEN ... ELSE .. tests ; we use mathematical symbols in their place. The following are the mathematical symbols we can use in Basic tests : > greater than < less than = equal to >= greater than or equal to <= less than or equal to <> not equal to Having covered those two issues, what DOES the above code actually do? A) If the player selects the slow game and is older than 29, we print the "too old?" message and change start.speed from 40 back to 30. We only do this if the condition above is true (in other words the player IS older than 29 AND selects the slow game). Notice that we have more than one action to be taken when this condition is true. In this case, each action after the THEN instruction has to be on its own separate line. When all actions that we want to perform when this condition is true have been entered, the condition or test has to be closed with an ENDIF command , again on its own line. Notice the brackets around the condition. In Basic, you can code very complex conditions in one statement (although it's not recommended that you do) and you can also use the OR operator ; for example IF ( (condition1 AND condition2) OR condition3 ) THEN .. Use brackets to clarify the groupings of your conditions to reduce logical errors and clarify reading your program. B) After the first condition has been tested, we drop down to the next condition (age < 8) and print the "too young" message if the condition is true. Notice in this line that since we only had one action (the PRINT action) we can code the whole " IF condition THEN action " on one line and we don't need an ENDIF at the end. C) After the second condition has been tested, we then include a further test - whether the player has selected the fast game. If the player HAS selected the fast game, we print the "wake up" message. If the player has not selected the fast game then the ELSE code will print the "take the easy option" message. Either way, we will print one of the two messages. Your IF condition has to be coded on one line; it cannot span two lines. Where you are entering a long IF condition , the line you're on will automatically move across to give you more room to complete the condition. When you press the Enter key, you'll go back to column one of the next line. Try this out. Enter a long comment line (the line should start with a quote or the characters REM), then press the enter key. Now, with your cursor back on the long line, press the END then the HOME keys on the keyboard one after the other and watch what happens. You'll flip between the end of the line and the start of the line. If you hold the CTRL key down and, at the same time, press the left or right arrow keys, you'll go through your long line word by word. It's a very good idea to INDENT your IF statements to improve readability just like we've done in the above code (INDENT means to move the commands that are part of the IF and action logic to the right by a couple of columns). NESTED IF's You can also have an IF statement following an IF statement. This is called NESTED IF's. To have more than 2 levels of NESTED IF's is not recommended since it really makes your program quite complicated to read. Having said that, here's the format: IF condition.1 THEN action.1 IF condition.2 THEN action.2.1 action.2.2 ENDIF ENDIF You'll note that each IF has to have a matching ENDIF. In this example, if condition.1 is true, the program will do action.1 and then it will test for condition.2. If this is true as well (and only if it's true) then the program will also do action.2.1 and action.2.2. If condition.1 is NOT true, the program will never get to the statement that tests for condition.2 We could have coded the first condition in our program above as follows: IF age > 29 IF game.speed$ = "S" start.speed = 20 PRINT "Getting too old to play the fast game?" ELSE PRINT " I'm impressed! Think you can do it?" ENDIF ENDIF In the example above, it will only test for game.speed$ = "S" when age is greater than 29 and also the ELSE condition (the "impressed" message) will only print when age is greater than 29 and game.speed is NOT "S" If game.speed is NOT S then it must be F, right? WRONG! We don't test after the player has entered the game speed that they actually DID enter an S or an F. (We'll explain how you can do that later). So they could have entered T or X or anything. Can you see what program BAS05.BAS will do if they enter T? They'll get set up to play a fast game, since start.speed is set to 40 before the IF conditions and is only changed to 30 when the first IF condition is true. However, the IF game.speed$ = "F" line will print the "easy option" message because game.speed$ is NOT equal to "F" (it's a "T"). If you follow this , then you're REALLY starting to think like a programmer..... watch out, it could be FUN! You can test for anything you want in these IF THEN ELSE conditions, even for specific names that have been input like: IF name$ = "dad" THEN points.per.hit = 1 ELSE points.per.hit = 100 ENDIF but you wouldn't do that, would you? That would be cheating! Here's a program for you to follow now: IF you are not quite sure how this all works THEN try making some changes to the program and see what happens ELSE carry on with the next subject ENDIF 4.8 BASIC COMMAND: GOSUB xxxxxxx ______________________________________ What we have been working with so far is one program routine - the main routine. But a main program routine can re-direct processing (or call) a sub-routine - this is a block of code that performs a sub- function within the main program. For example you might want to calculate peoples ages from their date of birth and the current year (which might have been previously set-up in the program) in various places in your program. When you have such a routine (that is the name we give to a chunk of program code that performs a specific function) that will be executed in various places in your program, rather than duplicate the commands each time, you can simply include all the program commands in one subroutine and then, each time your program comes to the point where it wants to execute the commands, you would simply write GOSUB CALC.AGE (for example). When Basic is processing your program and comes to a GOSUB command, it then processes all the commands that are in the subroutine that you've written before continuing with the next command in the main program. However, you must be aware of the following to use GOSUB: A) Your sub-routine has to start with a label at the front that is the name you have called your subroutine followed by a colon character (:), and it must be followed by all the code you want in the sub routine. B) At the end of your subroutine, you must include a RETURN command, which tells Basic to return to the statement in the main program that follows the GOSUB statement. C) ALL Subroutines must be located at the end of the main program - they cannot be at the top or middle. D) Sub routines can call other subroutines. But be careful you don't call the same subroutine you're currently executing. This is called RECURSIVE CALLS, and may result in your program LOOPING. This means that it loops through a couple of instructions without EVER getting out (and getting very dizzy in the process!) The following is an example of a Recursive CALL: 'Main Program code........ . GOSUB LOOPTEST . END 'Subroutine code.......... LOOPTEST: <----< This is a A = 1 | | tight LOOP! GOSUB LOOPTEST ->-->- RETURN When something like this is coded and you run your program, it will give you an error message saying "Out of Stack space". Subroutines provide a handy way of reducing your program size and complexity when you have procedures that need to be executed from different places in your main program. Demo Program BAS06.BAS Here is an example of a subroutine. Load program BAS06.BAS. In this program, we've taken all the code we put at the top of our program we were just working on, and placed it in a subroutine called GET.NAME which has, as its last line, the RETURN command. At the top of the program, where we took this code from, we now have one command saying GOSUB GET.NAME 4.9 BASIC COMMAND: DO WHILE ... LOOP _____________________________________ This command allows you to set up a controlled loop situation. What does this mean? Well, sometimes you may want to repeat a section of code until a specific event happens. As an example, you might want to get input from the user for the variables above, then process the program, then go back and do it all over again until the user tells the program to stop. The format of the DO WHILE command is as follows: DO WHILE condition action 1 action 2 action 3 . . LOOP What will happen when the program execution gets to the DO WHILE instruction? Well, it will test if the condition is true. If it is true, it will perform all the actions between the DO WHILE line and the LOOP line. When it gets to the LOOP line, it will go back, check the condition again and, if it is still true, it will repeat the process again. It will continue doing this until the condition is false. When this happens, processing will continue from the line immediately following the LOOP statement. Demo Program BAS07.BAS Load program BAS07.BAS There are two examples of DO WHILE loops in this program. The first example in this program is in the GET.NAME subroutine, where we ask whether the player wants to play a slow or fast game. We have included a DO WHILE loop as follows: DO WHILE (game.speed$ <> "F" AND game.speed$ <> "S") INPUT "Do you want to play the slow or fast game(s/f)";game.speed$ game.speed$ = UCASE$(game.speed$) LOOP This code checks that the player enters an F or an S for game.speed$. The first time the program comes to this line, the variable game.speed$ has not been defined, so it will have a value of spaces. Since it's spaces (and therefore not equal to an S AND not equal to an F) then both our AND conditions are true so the program goes into the DO WHILE loop and asks for game.speed to be input. Now, lets say the player enters a value of "T". When the program comes to the LOOP instruction, it goes back to the DO WHILE instruction and tests the condition again. This time through, game.speed$ is still not equal to "F" and not equal to "S" so the program goes into the DO WHILE loop again. It will keep asking for game.speed until the player enters either an S or an F. The second example is in the main program, where we have coded the following: play.it.again.sam$ = "Y" DO WHILE play.it.again.sam$ = "Y" CLS GOSUB SETUP end.of.game$ = "N" DO WHILE end.of.game$ = "N" GOSUB GAME LOOP INPUT "Play it again? (Y/N) : ", play.it.again.sam$ play.it.again.sam$ = UCASE$(play.it.again.sam$) LOOP END This block of code has a DO WHILE ...LOOP within a DO WHILE.... LOOP (NESTED DO's!). The outer (or first ) DO WHILE.... LOOP controls how many times we play the game while the inner DO WHILE.... LOOP is the main program loop in our program that calls the Game. The subroutine GAME includes the basic instructions for our game. When the game finishes, (for example, all the aliens are shot out of the sky, or they shoot our cannon) the code in our GAME subroutine will set the variable end.of.game$ equal to "N". When this happens, the inner DO WHILE... LOOP will be cancelled and the instruction below it will be processed - the INPUT instruction asking if the player wants to play the game again. The program then comes down to the LOOP instruction below this one, which tells it to go back to the DO WHILE play.it.again.sam$ = "Y" line (since the inner loop has been cancelled). It then tests if the variable play.it.again.sam$ is "Y". If they had answered anything other than "Y", then the program will cancel the outer DO WHILE... LOOP and will continue its processing from the instruction immediately below the last LOOP command, which is END (terminate the program). If they had answered "Y", then the program will set end.of.game$ equal to "N" then activate the inner DO WHILE.... LOOP again and re-start the game. Why did we set the variable end.of.game$ equal to "N" before we went into the DO WHILE loop? Do you know? Well, what would happen if we left it out? Move the cursor to the front of the end.of.game$ = "N" line and enter REM or a single quotation mark (this turns it into a comment line as opposed to a program line that basic will execute). When you run the program now, the game starts up, then goes immediately to the "Play it again?" line. What's happened? What's happened is that the program has skipped the REM end.of.game$ = "N" command and executes the next program command, which is now DO WHILE end.of.game$ = "N" but it doesn't know about end.of.game$ at this point since the only place the variable is mentioned now is in the GAME subroutine, where it sets it to "N" when the game finishes. So, end.of.game$ is not equal to "N" (it's blank or null) and the program bypasses all the code in the inner DO WHILE...LOOP section and goes to the next immediate instruction after the LOOP, which is the INPUT instruction asking if the player wants to play the game again. WARNING: YOUR PROGRAM CAN GET INTO A NEVER-ENDING LOOP SITUATION IF THE DO WHILE CONDITION NEVER GOES FALSE (ie end.of.game$ never gets changed to a value other than "N"). IF THIS HAPPENS, PRESS THE CONTROL and BREAK KEYS AT THE SAME TIME TO STOP YOUR PROGRAM. There's only a few more pages to read, then we'll get into some really fun stuff, so hang in there! OK? 4.10 BASIC COMMAND: FOR .... NEXT _______________________________________ Where we know that we want to execute a process or section of code a specific number of times until we move on to the next process in our program, we would use the FOR ... NEXT command. It's format is FOR numeric.variable = start.value TO end.value STEP step.value . . NEXT numeric.variable Let's take an example. Lets say we wanted to calculate the squares of numbers from 1 to 10. (The "square" of a number is the number multiplied by itself. Don't ask me why we want to calculate this, but we do, OK!) Demo Program BAS08.BAS Load program BAS08.BAS Here's the code: CLS FOR Number = 1 to 10 Square = Number * Number PRINT "Square of " ; Number ; " is " ; Square NEXT Number END This is how the FOR .... NEXT instruction works: A) When Basic first comes to the FOR Number = 1 to 10 line, it will set up a control loop based on Number, which it initially sets to 1. B) Then it executes all the following code using Number with a value of 1 until it reaches a NEXT instruction. C) When it reaches a NEXT instruction, it adds one to Number and goes back to the top line ( FOR Number = . . . . ). D) The first thing it does now is test to see if Number is between 1 to 10. It is, (Number is now 2) so it goes through the code again, but this time with number set to 2. When it gets to the NEXT instruction, again it adds 1 to Number (making it 3) and goes to the top again. And so on, until number is equal to 11. E) When this happens, the program will cancel the FOR NEXT Loop (since number is not between 1 and 10) and continue with the instruction following the NEXT Number line. The numeric variables 1 and 10 after the FOR Number command could have been formulas; for example FOR Number = (low.num * 2) TO (high.num / 3) WARNING: BASIC WILL BYPASS THE FOR..NEXT CODE IF, WHEN IT GETS TO THE "FOR NUMBER = .... " LINE IT FINDS THAT THE START VALUE IS ALREADY GREATER THAN THE END VALUE. If we had wanted to do this routine for every alternate number, we could have coded FOR Number = 1 to 10 STEP 2 . . NEXT Number Then, we would only have printed the squares for numbers 1,3,5,7 and 9 since, when Basic gets to the NEXT Number line, it adds 2 to Number and not 1. You will find some other examples of FOR . . NEXT LOOPS when we get into the GameBasic GAME commands, which won't be long now. 4.11 BASIC COMMAND: CALL xxxxxxxx (var1, var2, var3....) __________________________________________________________ The basic command CALL is used to run a sub-program. It is not in the scope of this document to explain the inner workings of sub-programs and how you code them. However, sub-programs are very similar to GOSUB routines, which we've explained above. The sub-program contains lines of code that get executed when the CALL is issued. You won't see the program code in your main program - you need to press certain key combinations to look at sub-programs. This command is included in this document since all GameBasic routines are written as sub-programs. Your game programs will make calls to these sub-programs and you therefore have to know something about how to pass variables to the GameBasic sub-programs. Each GameBasic sub-program expects to be sent a specific number of variables, each of a certain variable type (for example, a numeric variable followed by a string variable etc...). If a routine expects to get 5 variables, you must pass it 5 variables - no more and no less, and they must be of the variable types that the routine expects to receive. Sounds a bit confusing? Well, let's take a simple example to show how calls to sub-programs are made. Let's assume that you want to call a previously-written sub-program that prints a message starting at a specific row and column on the screen. The sub-program that was written expects to be sent three variables (or parameters) - row, column and message; in that order. When it is called, it will take the value of the variable supplied for the message parameter and print it at the location specified by the row and column variables supplied. Each time you call this sub-program, you can supply a different value for row, column and message and the sub-program will work with the new values. Here's an example of a call to this sub-program, which we've called PRINTMESS for the purposes of this example, asking it to print "START" at row 2, column 5: CALL PRINTMESS (2,5,"START") The first variable that PRINTMESS expects to receive is a numeric variable representing the row, followed by another numeric variable for the column followed by a string variable containing the characters that you want it to print. You must supply the variables (or parameters) in that order. Now what would happen if you didn't? Look at the following three examples of calls to PRINTMESS: row = 2 col = 5 mess$ = "START" CALL PRINTMESS (mess$, row, col)<-------- call no 1. CALL PRINTMESS (col, row, mess$)<---------call no 2. CALL PRINTMESS (row, col, mess$, reply$)<--- call no 3. Call number 1 won't work at all because PRINTMESS was told, when it was written, that the first parameter it will be sent will be a numeric parameter and here we are trying to send it a string parameter! Basic is smart - it says "Oh No No No ... ! , you can't do that, stupid". Actually, it's a bit more polite than that; it says PARAMETER TYPE MISMATCH, but we all know that it really wanted to say the former! When you see this message, it's telling you that one of the parameters you've included in your CALL list is the wrong variable type. Call number 2 will work, but do you think it's going to work correctly? Now, you're going to have to pay attention to this, so sit up straight and listen!. PRINTMESS expects to receive three variables in the following order - row, column and message. Call number 2 will only work properly if you really wanted to print START at row 5, column 2 (as opposed to row 2, column 5), because that's exactly what you're sending the PRINTMESS routine in its CALL parameters. It doesn't know (or even care) that you've called the variables you're passing to it "col" and "row"; as far as it's concerned, the first parameter it gets is the row, the second is the column and so on. It will take the value in "col" and use that for the row to start printing at, the value in "row" and use that as the column etc... Call number 3 will not work either, since we're sending PRINTMESS four parameters and we told it when it was written that it will be sent three. When you send more than or less than the correct number of parameters to a CALL routine, you'll get the Basic error "ARGUMENT COUNT MISMATCH". In other words, Basic is saying "Woa! You told me you were going to send me three parameters and here you are sending me 123! What gives?" Now, let's take an example of a real call to a GameBasic routine: One of the GameBasic CALL routines (the CALL CREATE routine) is a routine which you can call to create a sprite and start it moving (more about sprites later). The format for the CALL is CALL CREATE ( sprite.no, char.no, col, row, speed, pixspermove, direction, horiz$, vert$, track$) There are 10 variables in the brackets. When you call this routine you must include 10 variable names or values exactly. An example of a valid CALL would be start.row = 10 pixs = 4 vertical$ = "N" CALL ACTIVE ( 1, 3, 12, start.row, 20, pixs, 90, "Y", vertical$, "0") As you can see, numeric and alphabetic values can be passed to the routine by either including the actual number or characters (characters must be enclosed in quotes) OR including the name of a variable that contains the number or characters you want to pass to the routine. Each variable or value included in the brackets must be separated from the next one by a comma. When the routine has completed its processing, Basic will execute the next instruction after the CALL. 4.12 BASIC ARRAYS : DIM ____________________________ Arrays are not commands, they're a method of holding variables in memory, and are very easy to understand. Let's go back to our bucket's again. (remember them?) When we define an ARRAY, we can create a number of buckets (or variables) in memory, all of the same type (that is, all numeric or alphabetic) and give them a common name. Let's do this now. Let's draw 4 buckets and call them all PLAYER.NAME$ <--------------------PLAYER NAMES----------------------> | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ---------- ---------- ---------- ---------- 1 2 3 4 For each array that we use (and we can use and define a number of different arrays in our program), we must tell Basic at the very top of our program (not in a subroutine) about the array so that it can set up a special area in memory to hold the array values. We do this by the command DIM PLAYER.NAME$(4) The 4 in the brackets tells Basic that we want to have 4 buckets (or elements, which is what we call array buckets) in our array called PLAYER.NAME$ Now, we can enter a separate value into each element (bucket) by simply specifying which PLAYER.NAME$ element we want to put the value into; number 1, 2, 3, or 4 . We do this by using what we call a subscript, which is just a number or variable containing the number of the element (bucket) we want to point to. We would add "JOHN" to PLAYER.NAME$ element 1 by coding PLAYER.NAME$ (1) = "JOHN" <--------------------PLAYER NAMES----------------------> | | | | | | | | | | | | | | | | | | | | | | | | | JOHN | | | | | | | | | | | | | | | | | | | | | | | ---------- ---------- ---------- ---------- 1 2 3 4 If we also wanted to move "MARY" to the second element of our array we would code PLAYER.NAME$ (2) = "MARY" <--------------------PLAYER NAMES----------------------> | | | | | | | | | | | | | | | | | | | | | | | | | JOHN | | MARY | | | | | | | | | | | | | | | | | | | | | ---------- ---------- ---------- ---------- 1 2 3 4 We could also have used a variable name to indicate which element we wanted to move the value into. For example, subscript = 2 PLAYER.NAME$ (subscript) = "MARY" will do exactly the same as the previous example. Now, lets set up another array and call it TOTAL.SCORE It will also have 4 elements or buckets. Here's the code to do this: DIM TOTAL.SCORE(4) TOTAL.SCORE(1) = 2000 TOTAL.SCORE(2) = 4000 As you can see, we've also moved some values into the first two elements of this new array. <--------------------PLAYER NAMES---------------------> | | | | | | | | | | | | | | | | | | | | | | | | | 2000 | | 4000 | | | | | | | | | | | | | | | | | | | | | ---------- ---------- ---------- ---------- 1 2 3 4 Demo Program BAS09.BAS We can use arrays like this to hold players names and scores while our game is being played and show all the players names and scores on the screen each time a game ends. Retrieve program BAS09.BAS and look at the changes that we've added to the program at the top and also in a new subroutine called PRINTSCORES. The program now loops through the "Do you want to play again" process 4 times controlled by a variable called game.number. At the end of each game, we add the player's name to the next available element in PLAYER.NAME$ array then we add the score to the same numbered element in TOTAL.SCORE array then print out the full contents of each array before we start the next game. The example above is an example using two one-dimensional arrays, since each array has only one variable (one of them holds a name and the other array holds total points) and we only need one subscript to refer to each array's elements. But with arrays, we can have 2 or more dimensions. Visualising a 2 dimensional array is not difficult, but it gets increasingly more difficult to visualize three or more dimensions. However, you'll hardly ever have the need to have an array of more then two dimensions. Let's assume that we also wanted to hold the players age in an array. Now, we could simply set up another array and call it PLAYER.AGE But we could also add another dimension to the TOTAL.SCORE array. Let's call the array PLAYER.INFO rather than TOTAL.SCORE and we'll make it a two-dimensional array so that it can have an element to hold total.score as well as an element to hold player.age. The array can be visualised as follows: <--------------------PLAYER.INFO----------------------> | | | | | | | | | | | | | | | | | | | | | | | | SCORE | | | | | | | | | | | | | | | | | | | | | | | | ---------- ---------- ---------- ---------- 1 2 3 4 | | | | | | | | | | | | | | | | | | | | | | | | AGE | | | | | | | | | | | | | | | | | | | | | | | | ---------- ---------- ---------- ---------- 1 2 3 4 Because this array has two dimensions (there are elements down as well as elements across), we define the array as follows: DIM PLAYER.INFO ( 4, 2 ) The first number in the brackets, the 4, tells basic that the array is 4 elements wide. The next number, the 2, tells basic that the array is 2 elements deep. Now when we want to refer to a specific element in the array, we have to give two subscripts in our command; one to tell basic which column we want (from 1 to 4) and the other to tell basic which row we want (either the first row - that we're going to be using to store Score in - or the second row - that we're going to be using to store player's age in) Here is how we would store player 3's score and age: PLAYER.INFO( 3, 1 ) = score PLAYER.INFO( 3, 2 ) = age <--------------------PLAYER.INFO-----------------------> | | | | | | | | | | | | | | | | | | | | | | | | SCORE | | | | | 23000 | | | | | | | | | | | | | | | | | | | ---------- ---------- ---------- ---------- 1 2 3 4 | | | | | | | | | | | | | | | | | | | | | 15 | | | AGE | | | | | | | | | | | | | | | | | | | | | | | | ---------- ---------- ---------- ---------- 1 2 3 4 Now that's not too difficult, is it? Demo Program BAS10.BAS Retrieve program BAS10.BAS and look at the changes. In this program we've used a one dimensional array as in the previous program to store the top 10 player's names, and we've added a two dimensional numeric array called PLAYER.INFO to keep track of the top 10 player's scores and ages. At the end of each game, we display the top 10 players in descending total.point sequence. Unfortunately, when the players exit the game, all information about players and scores that we've been holding in the arrays is lost. To keep it, we would have to write the information to a file and read it back in at the start of each game. However, that is beyond the scope of this manual. 4.13 Basic Arrays : REDIM __________________________________ The REDIM Basic command is a handy way of resetting an array's values to either zeros (if it's a numeric array) or spaces (for a string array). The format of the instruction is: REDIM array.name ( n1, n2, . . ) where array.name is the name of the array you want to initialise and n1, n2 are the dimensions of the array. NOTE: The array must have been set up by a previous DIM instruction and the dimensions n1, n2 etc.. must not be greater than the dimensions the array was first set up with. AND NOW - THE LAST TOPIC BEFORE WE GET INTO SOME SERIOUS GAMES ! 4.14 DEBUGGING YOUR PROGRAM ______________________________ When you start testing a new program, you'll probably find that it's doing very strange things initially. You've got some errors in the program and you need an easy way to find them! Well, QBasic provides a method of de-bugging your program to help you find out where those errors are. We call program errors BUGS! This word came into common usage from the early days of computers, when they were made of valves instead of the chips that we have nowadays. One day, the computer the scientists were working on developed a problem which they couldn't explain until one of the scientists opened the computer and found a dead moth fused to one of the hot valves. After he removed the moth, the computer worked perfectly - but ever afterwards, whenever computers displayed errors (even programming errors) they are referred to as BUGS! Aren't you glad you know that now? Back to our discussion on debugging your program (or getting the moths out!). We're going to take program BAS10.BAS as an example, and show you the code that initially writes the 30 aliens to the screen. Retrieve the program now and page down through the program until you come to the SETUP subroutine. Look through that sub routine until you see the following code: ' ------- following block sets up alien sprites alien.spriteno = 10 FOR row = 10 TO 50 STEP 20 FOR col = 30 TO 300 STEP 30 CALL CREATE(alien.spriteno, 2, col, row, start.speed/10, start.speed/10, 180,"W","W", " ") alien.spriteno = alien.spriteno + 1 NEXT col NEXT row The CALL CREATE line is the line that sets up an alien character or sprite on the screen. We'll explain later what the values in the brackets mean. As you can see, this is a nested FOR NEXT block of code. For each of rows 10, 30 and 50 (since step value is 20) we create aliens in columns 30, 60, 90, etc... up to column 300 (since step value is 30) Let's watch this as the program actually performs the instructions, but before we do this, we're going to add one line to the program to help us in our debugging. Just before the CALL CREATE line, add the line LOCATE 20,1 : PRINT "Row="; row; "Col="; col (note that the colon lets us code two instructions on one line) Have you added the line? OK. Now bring the cursor to the FOR row = ..... line and press the F9 key. The line will now be highlighted. This sets up a break point in the program. What this means is that when we run the program and it gets to the line we've highlighted with the F9 key, Basic will temporarily stop the program and display our program code at this break point. Note that you can have multiple break-points on in your program at the same time, you're not just restricted to one. Just try it now. Press F5. This will start the program running. It will go through the regular steps where it asks for the players name etc,.. but after that (before the games starts) it will now break at the place you highlighted and you will see your program code on the screen at the breakpoint you selected. Now press F8. The F8 key tells Basic to perform the next instruction only. Using F8 you can step though your program one line at a time and watch how the program performs. So now we've performed the FOR row = ..... instruction, Press F8 again and it will perform the FOR col = .... instruction. You didn't see anything happen did you! That's because all the activity was internal, setting up the row and col loops. Let's see what row and col actually contain, shall we? Press F8 two more times. The line LOCATE 20,1: PRINT "Row="; row ; "Col="; col should now be processed but again, you didn't see anything right? It should have printed the values of row and col on the screen! Well, don't despair, it did. It's just that we're currently looking at the program and not the output screen. Press F4, and you'll flip to the output screen where you should see ROW=10 COL=30 printed, and the canon at the bottom of the screen. Now press any key and you'll flip back to your program code. Pressing F4 followed by any key will flip between the output screen and the program code. So now the line CALL CREATE.... is the next to be processed. If we pressed F8 now, we'd get passed to the first instruction in the CREATE sub-routine, and we'd then step through the entire subroutine, line by line. This is quite lengthy, and we know this works, so we tell Basic to process the whole subroutine (or procedure) and break when it gets back to our main program - the instruction immediately after the CALL CREATE line - by pressing the F10 key (Procedure step) instead of the F8 key. Press the F10 key now. Now flip to look at the output screen (press F4) and you should see the first alien on the screen. Press F8 four times then look at the output screen again and you should see that row is still 10 but col has been increased to 60. Now, when you run the program to the point after the CALL CREATE command and you press F4 you should see the second alien on the screen. Continue doing this for as long as you want and you will see all the aliens being written to the screen. You will also see the nested FOR instructions working. HINT: In Gamebasic, when we want to look at the contents of a variable, include the LOCATE x, x command before the print command. If you don't do this, then the PRINT command on it's own will move the screen up by one line and all your game characters will get moved along with it. HINT: After you've finished using a LOCATE x,x: PRINT line for your debugging, you can leave it in your program in case you need it again by simply inserting a single quote at the beginning of the line. It is now a comment line. When you want to use it again, just take out the quote. HINT: QBasic has a pretty neat field-sensitive HELP feature. When you're in the program edit screen and you're unsure of what a QBasic command does, position the cursor under the command (for example, under PRINT) and press the F1 key. QBasic will then show you a series of help screens on the PRINT command. Note that this doesn't work for GameBasic commands. HINT: Unless you have coded your own subroutines (GOSUB xxxx, remember?) and want to de- bug them, it will probably be easier if you use the F10 key all the time, instead of the F8 key. "Oh wonderful. NOW he tells us!" I can hear you saying. Sorry, but we had to cover the above so you understand the distinction between single-instruction steps (F8 key) and full-Procedure steps (F10 key). This debugging process is somewhat laborious, but it's the best that QBasic has to offer. Other languages (including Microsoft's QUICKBASIC, which is an upgraded version of QBasic) have much better debugging features. Well, that's it. If you've followed the above, then CONGRATULATIONS! At long last you're now ready to move on to some Games .... Get Ready ..... GO ! ________________________ 5. GAMEBASIC COMMANDS. ________________________ 5.1 Introduction. _________________ GameBasic provides many features to simplify the process of developing games. That's why it was developed; so you can concentrate on the logic in your game program rather than the technical complexities involved in displaying sprites on the screen, moving them around, testing if they've run off the side or if they've hit another sprite.. (remember our definition of a sprite being a character that appears on the screen, moves in a certain direction and speed and then (maybe) disappears...) You define how your characters will look by setting up char$ arrays containing your character definitions and then calling the DEFINECHAR routine. You create and start sprites moving through the CALL CREATE command and you set-up your control sprites (sprites whose movement you control through the keyboard, like a cannon etc..) through the CALL CONTROL command. The CALL CONTROL command is a very powerful command; in it you can define which character the control sprite should appear as depending upon it's aspect (in other words, when it's pointing up, down, to the left etc..), which keys control its movement and which character to fire when the CALL SHOOT command is issued. It's the command which has the greatest number of parameters in its CALL list and is the most powerful command in GameBasic - but normally you'll only need one of these commands in your game. Finally, there are CALL commands which allow you to test if a sprite is still active, change the character a sprite is being displayed as, delete a sprite, test if one or more sprites have hit each other and so on. Now we've covered some of the introductory aspects to GameBasic, I promised we'd get into programming, so let's do that now. We're going to work together to develop a pretty sophisticated computer game - we're going to do a version of Alien Invaders - where nasty aliens drop down the screen and take over the world. We'll have a cannon at the bottom of the screen which will be controlled by the keyboard and can fire missiles up at the aliens. We'll have to test if a missile has hit an alien, if we've hit all the aliens, if the aliens have hit our cannon and also if the aliens have landed.. First, we have to do a flowchart of the logic that we want in our program. Can you have a go at that now! Don't look over the page at the answer yet (although in programming, there is hardly ever one and only one answer or solution!). Here's one suggested flow chart, which we'll be working with as we develop our program. Define Characters (alien, cannon, missile, fireball) | V Create Alien and Cannon sprites Define Control Sprite (cannon) | V -->------->Move Sprites | | | V Yes | FIRE key pressed? -------->Launch Missile | | | ^ No |------------<----------< | | | V Yes Yes | Is a missile active? --->Has it hit--- | | an alien? | | | | V | | | Delete Missile | No V No V Delete alien | | | Add to score | | | | ^ |-------<-----------<---- | | | V Yes | Are all aliens hit?--->Print"WellDone" ^ | Stop | No | | V Yes | Has Alien hit cannon? ---->Print"You got | | hit" | No V Stop | | Yes ^ Has Alien landed? ---> Print"We Landed" | No | Stop | (Loop Back) | -<-------------<- We're going to develop this program in stages, taking each stage at a time and gradually introducing you to GameBasic CALLs and the parameters you have to pass to them. First, we're going to define our characters and just display them on the screen to make sure we've got them exactly how we want them. 5.2 GAMEBASIC BASE PROGRAM ____________________________ Demo program GAME01.BAS Get into the Basic environment and retrieve program GAME01.BAS As soon as you have got the program in the edit screen, save it under a different name so you can call back GAME01.BAS later if you need to. Remember, you save the program as a different name by pressing Alt then F then A, then you enter the name you want to call it (GAME01xx where xx is your initials - you don't have to put .BAS at the end, Basic will do this for you automatically). As you work through the following, save each GAME program under your own initials as above. Look at the program. What we are working with now is the GameBasic "Base" program with some lines of code added to define your characters. There are a couple of lines at the top of the program and also at the bottom which are GameBasic program lines. This code (another name for a block of program lines) is boxed by asterisks to identify it as GameBasic code. YOU MUST NOT CHANGE ANY OF THESE LINES OR ELSE GAMEBASIC WILL STOP WORKING. In between these top and bottom blocks of lines is the code to define and display your characters. Also, the program includes all the GameBasic CALL Sub Programs - you can't see these but they are there (NOTE: Basic provides special keys to look at sub programs but it's not in the scope of this manual to explain this aspect of Basic) Whenever you start coding a new program, you will call up the GameBasic "BASE" program GBASE.BAS and immediately save it with the name you want to give to your new game program. All subsequent programming you do will be done with YOUR program's name - YOU CAN'T CHANGE THE BASE PROGRAM. Look at the code between the GameBasic code. See how we have defined the alien, cannon and missile characters? The cannon character is shown below. 5.3 CHAR$ - Character definition. _________________________________________ For each character you want to create, you simply fill-out a two-dimensional array of 16 horizontal dots by 12 vertical dots (ie a grid of 16 x 12) and tell the computer which colour you want each dot to be shown as. The combination of dots make up your character. You MUST use the array called char$ for this. The first dimension (ie the 1 in "(1,12)" for example ) represents the character number. In the example below, the character number for the cannon is 1. The second dimension represents the line of the character, and can go from 1 to 12. char$(1, 1) = " " char$(1, 2) = " " char$(1, 3) = " " char$(1, 4) = " " char$(1, 5) = " 7 " char$(1, 6) = " 7 " char$(1, 7) = " 373 " char$(1, 8) = " 33333333333333 " char$(1, 9) = "333 3 3 3 3 3 33" char$(1,10) = " 33333333333333 " char$(1,11) = " 6 6 6 6 " char$(1,12) = " 6 6 " HINT: To save internal memory where you have a lot of different characters, you can remove char$ lines which don't contain any numbers between the quotes (for example, lines 1, 2, 3 and 4 above). Also, to save internal memory space, you can place the last quote immediately after the last number in the line (for example, lines 5 and 6 could be shortened to char$ ( 1, 5 ) = " 7" etc...) The numbers between the quotes represent the colour of the pixel (or dot) on the screen as follows: 0 or space = Black or Background colour 8 - Grey 1 - Blue 9 - Light Blue 2 - Green A - Light Green 3 - Cyan B - Light Cyan 4 - Red C - Light Red 5 - Magenta D - Light Magenta 6 - Brown E - Yellow 7 - White F - High Intensity White Look at the definition for the other characters. Can you see how they will look when they're shown on the screen? 5.4 CALL DEFINECHAR ____________________ Example: CALL DEFINECHAR This is the GAMEBASIC command that actually reads your character definitions and turns them into screen definitions. It does not need any parameters in brackets after the DEFINECHAR. This process takes a couple of seconds, depending upon the speed of your computer and the number of characters you have defined. It is suggested that you define ALL the characters your game will be using up front and CALL DEFINECHAR once at the start of the game. 5.5 CALL CREATE (sprite.no, char.no, col, row, speed, pixspermove, direction, horiz$, vert$, track.no) ______________________________________________________________ Example: CALL CREATE ( 1, 1, 50, 10, 40, 6, 180, "D", "D", " " ) This is the command that creates a sprite, but before we discuss it, we should mention one thing. In the section that explained the PRINT command, we said that there were 25 rows and 80 columns on a screen. Well, that's true when you're "Printing" information, but GameBasic commands use graphics characters, and these use a different Screen "Mode" in Basic - Graphics mode. The only difference you have to be aware of is that instead of only being able to work with 25 rows and 80 columns, in graphics mode there are effectively 200 rows (from 0 to 199) and 320 columns (from 0 to 319) as shown below. (Note that the PRINT command can still only reference 25 rows and 80 columns - it's only the GameBasic graphics commands that can use the higher numbers ). Each of the following positions on the screen represents what we call a pixel - the small dots that go to make up the characters you see. That's what you are defining when you code your character definitions in char$ - where you want each pixel to appear in your character and what colour it should be. IN ALL GAMEBASIC COMMANDS THAT FOLLOW WHICH INCLUDE A ROW OR COLUMN PARAMETER, THE MAXIMUM VALUES YOU CAN ENTER FOR ROW AND COLUMN ARE 187 AND 303 RESPECTIVELY. Now look at the GAME01 program you have on your screen. In this program, we've created one sprite each for the cannon, alien and missile and defined them as sprite numbers 1, 2 and 3 respectively. Can you see the CALL CREATE command? The parameters that must be passed to the CALL CREATE subroutine are: sprite.no - This is a number from 1 to 90 representing the number you are assigning to this sprite. char.no - This is the character number that the sprite will be displayed as. The cannon is being set up as sprite.no 1 and is using char.no 1. The char.no is taken from the group of lines you used to define the character you want to use here (ie. from the array CHAR$(1,n) ) Char.no 1 happens to be (surprise, surprise) the cannon character definition. If we wanted this sprite to take on the shape of another character, we would have used another number. col - This is the column (from 0 to 303) where we want this sprite to be first displayed. row - This is the row (from 0 to 187) where we want this sprite to be first displayed. speed - This is the speed we want this sprite to start moving at. The value can be from 0 to 40. 0 indicates a sprite that doesn't move. This might be a land mine or a rock in a Tank Battle game, for example. 1 indicates a very slow moving sprite. 40 indicates a very fast moving sprite. Note that the sprite won't start moving until we issue the CALL MOVE command (see next). pixspermove - The number of screen pixels that this sprite should move by every time it moves.This value is normally from 1 to 6. A low value will give a smooth-moving (but somewhat slower) sprite. A higher value will give a faster moving sprite but its motion may appear more jerky. direction - This is the angle at which the sprite should move. 0 degrees is straight up. 90 degrees is to the right 180 degrees is straight down. 270 degrees is to the left. In-between values can also be defined. For example, a sprite that moves diagonally from the bottom left to the top right would have an angle of 45 degrees. horiz$ - This parameter is a string parameter and should be enclosed in quotes. It defines what should happen to the sprite when it reaches a screen edge while it is travelling horizontally (ie the left or right side of the screen). "W" - sprite will wrap around the screen, appearing on the opposite side (like an alien descending at an angle) "D" - sprite will be deleted "S" - sprite will stop when it reaches the edge (ie, a cannon) "B" - sprite will bounce off the edge. vert$ - The same definition as above for horiz$, but controls what happens to the sprite when it reaches a screen edge while it is travelling vertically (ie the top or bottom of the screen). track$ - This is the letter of the track that this sprite should follow. For a more detailed explanation of tracks, see CALL TRACK in section 6.6. If you're not using the TRACK feature of GameBasic, enter a space or null here (""). NOTE: At any time on your program, you can re-create a sprite using the CREATE command, even if it is currently active. The current sprite will be deleted and the new one will be created. This is useful when the sprite has reached a screen border and you wish to re-position it. 5.6 CALL MOVE _____________________ Example: CALL MOVE This command MUST be included in the main loop of your program. This is the command that moves the sprite and should normally be the first command you code in your main-program loop. If you don't include this command, those pesky little sprites won't move at all. NOW IT'S FUN TIME. Press Alt, then R then S (Run, Start) - or alternatively, press F5 (which is the equivalent key to start running a basic program). You should now see your alien , missile and cannon sprites appear on the screen. Why does the line "Press any key to continue" come up on the screen? The reason is that we don't have a loop in the program just yet to continually execute the MOVE command. The program executes the MOVE command once, then comes to the end. Basic then steps in and says "OK, your program's finished, press any key to continue" - or words to that effect. We'll add a loop later, but for now you should practice making changes to the character definitions and the positions on the screen that the sprites are first displayed. Initially, only make one change at a time and watch what happens. If you really mess the program up, don't worry - you have two options. 1. You can retrieve the version you saved with your initials by pressing Alt then F then O, select the program version with your initials and reply "NO" when Basic asks if you want to save the program you've just been working on OR 2. You can retrieve the original GAME01.BAS program and save it again under you initials (GAME01xx), again replying "NO" when Basic asks if you want to save the program you've just been working on. Once you're happy that you can make these changes, carry on reading. Demo program GAME02.BAS OK - so you've just run your first GameBasic program. Not Bad! Now, retrieve the program GAME02.BAS Look at this program. It's very similar to the previous one, except that now we have included a couple of lines to set up a control loop around the MOVE command. Do you see them? Now, when you run this program, the sprites will move for a few seconds before the value in variable J is greater than 2000. NOW, PRACTICE MAKING CHANGES TO THE CALL CREATE COMMANDS - CHANGE THE SPEED, PIXSPERMOVE, DIRECTION, HORIZ$ AND VERT$ VALUES AND WATCH WHAT HAPPENS. Again, initially, only make one change at a time. Once you are happy and understand how changing the values changes the way the sprite moves, you can continue reading. Demo program GAME03.BAS Now retrieve program GAME03.BAS This program builds on what we've developed so far except for the time being we've stopped showing the missile sprite. We'll add the missile sprite back in later when we make it a sprite that's "fired" by the keyboard. Instead of displaying just one Alien sprite we've changed the program to display 30 aliens arranged in three rows of 10. To do this, we've used the FOR... NEXT instruction as follows: . alien.spriteno = 10 FOR row = 10 to 50 step 20 FOR col = 30 to 300 step 30 CALL CREATE(alien.spriteno, 2, col, row, 5, 5, 180, "W" , "W", " ") alien.spriteno = alien.spriteno + 1 NEXT col NEXT row . Let's explain what's happening here - it's not too difficult. A) Before we drop into the first FOR..NEXT loop, we set alien.spriteno equal to 10. We're going to number our alien sprites from 10 to 39 (that's 30 of them). After we've created each alien sprite through the CALL CREATE command, we add 1 to alien.spriteno so that next time through the loop the sprite number will be 1 higher (for example, the second time through the loop, alien.spriteno will be 11). B) After having set alien.spriteno to 10, we drop into the first FOR...NEXT loop. This does the following. Initially, it sets up a loop based on a variable we've called row with an initial value equal to 10. Then immediately after this, it sets up another FOR...NEXT loop based on a variable we've called col (Column) with an initial value of 30 (the first sprite on each row will be displayed in column 30). Next, the program creates the first alien sprite. It will be sprite number 10 (that's the value that's in variable "alien.spriteno" at this stage), character number 2 (our alien definition), row 10 (that's the value in variable "row" at this stage), and column 30 (that's the value in variable "col" at this stage). C) Now, we add 1 to the alien.spriteno (it now has a value of 11) and do the NEXT col instruction. This tells Basic to go back to the FOR col.. line, add 30 to the col value (30 is the value we want to increment col by), which will now contain a value of 60, and test if the value of col is greater than 300. Since the value of col is not 300 yet, the program will drop down to the commands following the FOR col.. line and create the next alien.sprite. This will be sprite number 11 and be displayed at row 10, col 60. D) The program will continue to create alien sprites on row 10 at ever increasing columns until the value of col is greater than 300. When this happens, the program will cancel the FOR col = . . . loop and drop down to the NEXT row command. E) Now it will add 20 to row (the increment or step value) making row equal to 30 (since it was previously 10), go back to the FOR row = . . . line, and test if row is greater than 50. Since it isn't, it will drop down to the FOR col line and set up a completely new loop based on col again with the variable col initially set back to 30. F) It will then create the alien sprites (10 of them) for row 30, then do the same thing for row 50. After row 50, it will cancel the FOR row = . . . loop and drop down to the command following the loops - all 30 of our alien sprites will have been set up NOW RUN THIS PROGRAM. Watch the aliens come down the screen. Because we said "W" (wrap) in the CREATE command, the aliens re-appear at the top once they get to the bottom. The program will stop once the value of variable J is greater than 2000. NOTE: When sprites cross each other, you will notice that where they cross, their colours change. This is a "feature" of QBasic graphics and is NOT a problem with your GameBasic program. 5.7 GameBasic Variable INKEY _______________________________ Demo program GAME04.BAS Now retrieve program GAME04.BAS Here, we have introduced a GameBasic variable that you can use in your programs. This is a numeric variable called INKEY. Each time the GameBasic CALL MOVE command is issued, it will place into INKEY a number representing the last key that was pressed on the keyboard since the last time that CALL MOVE was issued. You will be using the keyboard to control your game (in other words, when the player presses the space bar key, you may want your program to fire a missile..) You can use the INKEY variable to test which key was pressed and make your program take appropriate action. As an example, the number representing the space bar is 32. If no key was pressed, the value in INKEY will be zero (0). Please refer to Appendix A for a full list of key values. NOTE: For alphabetic keys A to Z, the INKEY variable will always contain the value for the lower- case letter, even though the Shift key may be on. This is a friendly feature so that you don't have to test for upper-case and lower case keys in your program. In this program, we have written a DO WHILE loop around the CALL MOVE command as follows: '***** Main program loop ************ DO WHILE INKEY = 0 CALL MOVE LOOP END Now, when you run this program, the sprites will continue to move until such time as any key is pressed on the keyboard. When this happens, INKEY will NOT be zero and the DO WHILE loop will terminate and the program will drop down to the END instruction. Press F5 (or ALT then R then S) to start this program running. Watch what happens. Now when you want the program to stop, press any key. Great! We're starting to put together a neat game, eh? Can you see it taking shape? Actually, this is how you will develop most games, after you've flowcharted the logic - step by step - so you get each section of your program working before you go on to the next section. Now we're going to get the Cannon to move across the bottom of the screen by getting the player to press the direction keys <- and -> Demo program GAME05.BAS Call up program GAME05.BAS. This is exactly the same as the previous program except for two changes. Firstly, we've added another line - the CALL CONTROL line. Can you see it? 5.8 CALL CONTROL (sprite.no, horiz$, vert$, pixspermove, "u", keyup, charup, shootdirectup, shootcharup, "d", keydown, chardown, shootdirectdown, shootchardown, "l", keyleft, charleft, shootdirectleft, shootcharleft, "r", keyright, charright, shootdirectright, shootcharright) _________________________________________________________________ Example : CALL CONTROL (1,"Y","N",2, "up", 0, 0, 0, 0, "do", 0, 0, 0, 0, "le", 75, 1, 0, 3, "ri", 77, 1, 0, 3) This is a very powerful command, and hence has the most number of parameters. However, don't despair - you probably only need one of these in your program, unless you're programming a two-player keyboard game. This command tells GAMEBASIC that a specific sprite number is to be controlled by the keyboard. For that sprite number, it also tells GameBasic whether the sprite can move horizontally and/or vertically, the number of pixels it should move each time, which keys control the sprite movement, the character the sprite should be shown as when it's moving in a particular direction (ie a spaceship pointing up the screen as opposed to pointing to the left) and, when the SHOOT command is issued for this sprite (see later), which character to shoot (ie a missile pointing up rather than a missile pointing to the left) and in which direction it should move. If you were developing a game for two players to play at the same time, like the TANK game in the Gamebasic demo program, you simply code one CONTROL statement for each of the sprites you want to have as keyboard-controlled sprites, telling Gamebasic which keys control which sprite etc.... sprite.no - a number from 1 to 90 representing the Sprite to be controlled. horiz$ - "Y" - the sprite can move horizontally. "N" - the sprite can't move Horizontally. vert$ - The same definitions as above for horiz$, but controls whether the sprite can move Vertically. pixspermove - This represents the number of pixels the sprite should move each time a control key is pressed. Enter a value of 1 to 100, where 1 is slow and progressive values are faster, but jerkier. A reasonable range would be from 1 to 6. "U", "D", "L", "R" - These are string parameters that are included to simplify reading the CALL CONTROL line and have no effect in the program. You can enter anything between the quotes - "UP", "left" etc.... keyup, keydown, keyright, keyleft -these parameters define which keys, when pressed, move the sprite in the specific direction. Enter the INKEY number for the key (see Appendix A for complete list of values). For example, spacebar = 32 Left arrow key = 75 F12 = 134 Right arrow key = 77 charup, chardown, charleft, charright - these parameters tell GAMEBASIC which character to display the sprite as when it is moving in a particular direction. For example, if we had a keyboard-controlled spaceship in the middle of the screen, if it was moving to the left you would probably want it to look different than when it is moving in any other direction. Remember to set up a char$ (see above) for each orientation (ie up, down, ..) of your sprite. shootdirectup,shootdirectdown,shootdirectleft,shootdirectright - when the SHOOT command is issued for this sprite (see later), these parameters tell GameBasic which direction to fire the projectile in depending upon the direction this sprite is facing. shootcharup, shootchardown, shootcharleft, shootcharright - - when the SHOOT command is issued for this sprite (see later), these parameters tell GAMEBASIC which character (char$) to use for the projectile to be launched - you can use a different character to "shoot" for each different direction in which your sprite moves. Now look at the GAME05.BAS program again. The other change we've made to this program is to the DO WHILE instruction. Instead of coding DO WHILE inkey = 0 we've changed it to say DO WHILE inkey <> 101 Do you know why? The answer is that in this program, you'll be pressing left and right arrow keys to move the cannon across the bottom of the screen, so as soon as you press one of these keys, inkey will not be 0. If we didn't change this DO WHILE instruction, then as soon as you pressed any key, the program would stop. We've changed the instruction to stop when the "E" key is pressed (INKEY number 101). The MOVE loop will continue as long as inkey is not equal to number 101 (the E key). Now press F5 (or ALT then R then S) to run this program. Watch the cannon move across the bottom of the screen when you hold down the left and right arrow keys! If you look at the CALL CONTROL command in the program, you'll notice that we have not entered any values for the parameters following the keyleft or keyright parameters. Neither have we entered any values for the keyup or keydown parameters (or the parameters following them). At this stage in the development of our game, our cannon sprite can only move to the left or right - it can't fire anything. Also, we haven't used the SHOOT command yet, so we don't need any of the parameters that follow the keyup, keydown parameters. (We'll get into the SHOOT command later). So, now we have our aliens invading us coming down the screen, and we have our cannon at the bottom of the screen and we can move it from left to right. Now, wouldn't it be nice if we could fire a missile and knock those aliens out of the sky? Well, first things first. Lets get our cannon to fire a missile when we press the space bar. Demo program GAME06.BAS Call up program GAME06.BAS. This program builds upon the previous program. Here, we've added a few lines in our main program loop to fire a missile when the space bar is pressed. next.missile.no = 40 '****** main program loop *********** DO WHILE inkey <> 101 CALL MOVE ' Test if spacebar pressed and we have to fire a missile IF inkey = 32 THEN CALL SHOOT(next.missile.no, 3, 1, 0, 40, 7, "D", "D") next.missile.no = next.missile.no+1 IF next.missile.no > 44 THEN next.missile.no = 40 ENDIF LOOP Firstly, we're going to allow 5 missiles to be in-flight at the same time, using sprite numbers 40 to 44. (Remember that we've numbered our 30 aliens from sprite numbers 10 to 39). To do this, we set up a variable called next.missile.no before we go into our main program loop, and give it a value of 40. After we've fired a missile, we add 1 to this variable. So, after we've fired our first missile, it will have a value of 41. We use this variable to represent the sprite number in the CALL SHOOT command. When the value of next.missile.no gets to be greater than 44, we re-set it to 40. Neat, huh? 5.9 CALL SHOOT (sprite.no, charno, from.spriteno, to.spriteno, speed, pixspermove, horiz$, vert$) ________________________________________________________________ Example: CALL SHOOT(40, 3, 1, 0, 40, 7, "D", "D") When this command is issued, a sprite is created using the character definition referenced by charno, starting at the location of the sprite referenced in from.spriteno aimed towards the sprite referenced in to.spriteno at the given speed and pixelspermove. If the from.spriteno is a keyboard-controlled sprite (like a cannon) and to.sprite is entered as 0 (zero), then the direction for the shoot sprite to move in will be taken from the CALL CONTROL parameters coded. sprite.no - A number from 1 to 90 representing the sprite to be created for this projectile. charno - the character number for this sprite (see char$). If the from.spriteno parameter that follows is one that is controlled by the keyboard, then the shootchar value in the CALL CONTROL command will override this character number. from.spriteno - the sprite number which is firing this projectile. to.spriteno - the sprite number to which this projectile should be aimed. If 0 (zero) is coded and the from.spriteno is one that is controlled by the keyboard, then the direction is taken from the CALL CONTROL parameters for that sprite. speed - the speed the sprite should start moving at, from 0 to 40. 0 represents a sprite that doesn't move (until you change its speed with a CALL MOTION command, as described later). 1 is slow; 40 is fast. pixspermove - the number of screen pixels that this sprite should move. This value is normally from 1 to 6. A low value will produce a smooth-moving (but slower) sprite. A higher value will give a faster moving sprite but its motion may appear more jerky! horiz$/vert$ - defines what happens to the shoot sprite when it meets a screen border, as in previous commands above. Before we run this program, notice the changes that we've also made to the CALL CONTROL command. We've changed the parameters to specify which character to use as a missile when the SHOOT command is issued and the cannon is moving either left or right. (the shootcharleft and shootcharright parameters are both coded as 3 - the definition for a missile going up - since we want to fire a missile directly upwards (zero degrees) regardless of whether the cannon is moving to the left or to the right). Now, press F5 (or ALT then R then S) to run the program. When the program starts, move the cannon with the left and right arrow keys to position the cannon below a alien - then press the space bar. You should see a missile launched from the canon directly upwards. (You can press 'E' to stop the program). When the missile gets to the top of the screen, it's deleted. That's good, right? But what happens when the missile actually hits one of the aliens? NOTHING! It goes right through it! That's because we haven't added any code in our program to test to see if any of our missiles have hit any of the aliens. That's going to be our next exercise. Demo program GAME07.BAS Retrieve program GAME07.BAS This program is the same as the previous one, except we've added some more code to the main body of our DO WHILE loop. 'Test if any missiles have hit any aliens FOR missile.no = 40 to 44 CALL ACTIVE(missile.no, 0, missile.active) IF missile.active = 1 THEN CALL CHECKHIT(missile.no, 10, 39, 8, alien.no) IF alien.no > 0 THEN CALL DELETE(missile.no, 0) CALL DELETE(alien.no, 0) END IF END IF NEXT missile.no This code is doing the following: For each of our five possible missiles that we can launch (controlled by the FOR missile = 40 to 44 loop) we're checking to see if the missile is actually active (in other words, it's been fired and has not yet hit an alien or got to the top of the screen) If it IS active, then we check if it has hit an alien! If it has hit an alien, we delete the alien and the missile, then go back and do the same process for the next missile until we've checked all missiles. The above code introduces us to three new GameBasic commands, which we'll explain one at a time: 5.10 CALL ACTIVE ( sprite.no1, sprite.no2, return-value) __________________________________________________________ Example: CALL ACTIVE (40, 0, num.active) This is a GameBasic command that will tell us whether one or more sprites are currently active on the screen. sprite.no1 - enter a number from 1 to 90 representing the first sprite number you wish to check for. sprite.no2 - if you wish to check for a range of sprites (ie from numbers 20 to 40), then enter the last sprite number you wish to check here. If you enter 0 (zero) as this parameter, the routine will only check for sprite.no1. return-value - You should enter a numeric variable name to receive the value returned. What will be placed in this variable after the routine has been called will be the total number of active sprites in the range defined. In the program GAME07.BAS, we've substituted the numeric variable missile.no for sprite.no1 and the other numeric variable missile.active for the return-value. Sprite.no2 is coded as 0 (zero) since we don't want to check for a range of sprite numbers, just for one specific missile. Now you might say, "Why not check for all missiles using this one command"?. If we did that, then all we would get back from the CALL ACTIVE command might be the value of 2 in missile.active - in other words, we would find out that there are two missiles active, but we wouldn't know which ones they were. For what we want to do at this stage in the program, that would be of little help. We need to execute the code following the CALL ACTIVE only for active missiles, and we need to know the missile number each time we execute the code. That's why we've set up a FOR ... NEXT loop based on missile.no 5.11 CALL CHECKHIT ( sprite.no, target.sprite1, target.sprite2, tolerance, return-value) _____________________________________________________________ Example: CALL CHECKHIT ( missile.no, 10, 39, 8, alien.no) This is the GameBasic command which tells us if a specific sprite has collided with any other sprites in our game (ie has a missile hit an alien?). Non-moving sprites, like rocks or land mines, will be checked if they fall within the sprite number range you specify. Non-active sprites (ie sprites that have previously been deleted) will be ignored. sprite.no, target.sprite1, target.sprite2 - There are three options to this command which are controlled by the presence or absence of values in target.sprite1 and target.sprite2. You can check 1 to 1, 1 to ALL, and 1 to Range. 1 to 1 : checks if one specific sprite has hit one other specific sprite. Enter sprite.no and target.sprite1. (target.sprite2 must be 0.) 1 to ALL : checks if one specific sprite has hit ANY OTHER active sprite. Enter sprite.no. (target.sprite1 and target.sprite2 must be 0.) 1 to Range : checks if sprite.no has hit any of the sprites in the range between target.sprite1 and target.sprite2, which must both be entered. tolerance - Enter a numeric value which represents the accuracy of the check you want. Distance between two sprites is measured from both sprites top left current positions. If a low number is entered for tolerance (for example, 4), then the sprites will have to be very close to each other to register a "hit". If a larger number is entered (ie above 10 ..), then a hit may be registered although it may appear on the screen that the sprites are not touching. return-value - enter a variable name here. The routine will put into this variable the first sprite number in the target sprite range that has registered a hit. If no sprites register a hit, the value is zero. In our program GAME07.BAS, we're checking to see if the current missile (missile.no) has hit any of the alien sprites (sprite numbers 10 to 39) so we're using the Range option. What we get back in the variable alien.no after issuing this command is either 0 (which means that this missile hasn't hit an alien) or the sprite number of the alien that the missile has hit. So, if alien.no is greater than 0, we know that we've hit an alien, and we have the alien's sprite number in the variable alien.no (which was returned to our program by the CALL CHECKHIT routine). We can then use the variable alien.no to delete the alien, which brings us nicely into the next subject: 5.12 CALL DELETE (sprite.no1, sprite.no2) ____________________________________________ Example: CALL DELETE (10, 0) We use this GameBasic command to delete active sprites. sprite.no1 - enter the first sprite number you wish to delete. sprite.no2 - if you wish to delete a range of sprites, then enter the last sprite number in the range you wish to delete. This parameter must be present. If you only want to delete one sprite, then enter 0 for this value. In our program above, we CALL DELETE to delete the alien sprite when it's been hit by a missile (it's sprite number is in the variable alien.no which we pass to the CALL DELETE routine) and also to delete the missile (it's sprite number is the value that's currently in the variable missile.no). Now, run this program by pressing F5 (or ALT then R then S). Now, move the cannon under a alien and press the space bar. You should get a missile going up and, if your aim is good, when the missile hits an alien both the alien and the missile will be deleted. Practice changing the tolerance value in the CHECKHIT command to see when it registers a hit and when it doesn't. When you're happy that you follow the above, then "Read on, McDuff!" (with apologies to Shakespeare). We're nearly getting to the end of programming our first complete game. Just a few more things to do. If you don't hit all the aliens before they reach the bottom of the screen, what happens? Nothing! It would be a good idea to add some code to stop the game and display a message like "Ha, ha! We've landed - you lose!" Also, if you're a really good shot, and you hit all the aliens before any one of them gets to the bottom of the screen - nothing happens!. Again, we should add some code to handle this condition - maybe displaying a message like "You got us! Well done!" Demo program GAME08.BAS Retrieve program GAME08.BAS This program builds on the previous program (as you probably guessed). Firstly, we've changed the main DO WHILE inkey <> 101 loop that keeps the game going as follows: end.of.game$ = "N" DO WHILE end.of.game$ = "N" CALL MOVE . . program commands... . . LOOP What this does is let us control when the game ends. The game can end when a number of situations happen. One such situation is when we've hit all the aliens. Another is when an alien lands (reaches the bottom of the screen). When these situations occur, all we do is move "Y" to the variable end.of.game$ and this will stop the DO WHILE loop since end.of.game$ is not "N" any more. The first line sets end.of.game$ to "N". If we didn't set end.of.game$ equal to "N" before we go into the DO WHILE loop, we'd drop right through the program and stop immediately. Here's the code we've added to test if a alien has reached the bottom of the screen: FOR alien.no = 10 to 39 CALL INFO(alien.no, row, col, s, d, c, d$, p) IF row >= 180 THEN end.of.game$ = "Y" DO WHILE ip$ <> "M" CLS LOCATE 10, 5 PRINT "We've landed - you lose" INPUT "Press M to continue", ip$ ip$ = UCASE$(ip$) LOOP END IF NEXT alien.no Before we explain the CALL INFO command, let's discuss what the above code is doing. First, we set up a FOR ... NEXT loop to process each alien sprite in turn. For each alien sprite, we test to see if it has reached row 180 (by using the CALL INFO command to get it's current row). If it has, we set the variable end.of.game$ to "Y" (to stop the main DO WHILE loop next time through and make the program go to the end) then we clear the screen and print a message. Finally, we set up a DO WHILE loop continually asking the player to press M to continue. Unless the player presses M, the program will do nothing else. Why do we do this? Well, it's for safety while you're developing your game. You'll find that when you're playing your game to test how it runs, you'll be pressing the direction and spacebar keys so quickly that you may not notice that the program ended. When the program ends, Basic displays it's regular "Press any key to continue" line and then passes you straight back to your program in edit mode. If you don't put a pause in somewhere, you could end up with some of the keys you were pressing in your game being written to your program code unexpectedly. Adding this code above forces the player to hit a specific key (which should not, obviously, be a key you're using in your game) to get back to the program edit screen. (NOTE: An easier way of doing this is to use the GameBasic TEXTSCREEN routine described later) Now lets explain the CALL INFO command. It's very easy. 5.13 CALL INFO ( sprite.no, col, row, speed, direction, char.no, hit.edge$, pixspermove) _________________________________________________________ Example: CALL INFO ( 1, c, r, spd, direct, character, edge$, p ) This GameBasic command will return information on a specific sprite. sprite.no - Enter the number of the sprite for which you want information. col - Enter a numeric variable name into which the routine will place the sprite's current column. row - Enter a numeric variable name into which the routine will place the sprite's current row. speed - Enter a numeric variable name into which the routine will place the sprite's current speed. direction - Enter a numeric variable name into which the routine will place the sprite's current direction. The value will be an angle measured in degrees from the top of the screen clockwise; as was discussed in the CALL CREATE command. char.no - Enter a numeric variable name into which the routine will place the sprite's current character number that it is being displayed as. hit.edge$- Enter a string variable name into which the routine will place the following information. "T" - sprite has just hit the top of the screen. "B" - sprite has just hit the bottom of the screen. "L" - sprite has just hit the left edge of the screen "R" - sprite has just hit the right edge of the screen. pixspermove - Enter a numeric variable into which the routine will place the number of pixels this sprite currently moves each time. Now look at the code we added to this program to check whether we've hit all the aliens. It's very similar to the code checking if an alien has landed. 'test to see if we've hit all the aliens CALL ACTIVE ( 10, 39, aliens.left ) IF aliens.left = 0 THEN end.of.game$ = "Y" CLS DO WHILE ip$ <> "M" PRINT "Good shooting - you got us all" . . LOOP END IF Here, we're using the CALL ACTIVE command to test for a range. The range is from 10 to 39, which represents all the alien sprites we set up. If none of them are active, we've just hit the last one! Now run the program and see what happens. Press F5 (or ALT then R then S). Now we're getting there. But it's pretty easy to get them all, isn't it. Let's try and make it a bit more difficult. We're going to do two things with the next version of our program. Firstly, we'll get the aliens to shoot a fireball straight down at the cannon and add some code to test if the cannon's been hit - if it has we'll stop the program. Then, we'll change the program to make it necessary to hit an alien twice before it gets deleted. We'll use the CALL CHANGECHAR command to change the aliens character after the first hit. Demo program GAME09.BAS Retrieve program GAME09.BAS This program builds on the previous one (as if you didn't know!). Firstly, we've defined a new character in char$ (4,..) to represent an alien fireball and also we've added a section of code in the main program loop to test whether there is an alien fireball active. If there isn't, we'll create a fireball going straight down. Also, we'll test to see if the fireball has hit the cannon. Here's the code to create the fireball: 'test if fireball active CALL ACTIVE ( 4, 0, fireball.active ) IF fireball.active = 0 THEN CALL RAND ( 10, 39, random.alien ) CALL ACTIVE ( random.alien, 0, alien.active) IF alien.active = 1 THEN CALL INFO (random.alien,col,row,s,d,c,e$,p) CALL CREATE (4,4,row,col,40,5, 180, "D", "D"," ") END IF END IF First, we're checking if sprite number 4 (the sprite number we're assigning to a fireball) is active at the moment. In other words, if there's already a fireball on the screen, don't create another one. If there is no fireball active (ie fireball.active = 0) then we use the GameBasic CALL RAND command (which will be explained next) to get a random number between 10 and 39 to represent the firing alien. If the firing alien that we come up with is active, we get it's row and column location and then create a fireball sprite coming directly down from that location. (It would seem strange if a deleted alien could still fire a fireball but I guess it could if it was "cloaked" like the Clingons!. However, in our program at the moment, it can't). Here's the code to test if the fireball has hit our cannon: (note that our cannon is sprite number 1 and the fireball is number 4) 'test if fireball has hit our cannon CALL CHECKHIT (1, 4, 0, 6, hit ) IF HIT > 0 THEN end.of.game$ = "Y" DO WHILE ip$ <> "M" CLS LOCATE 10,5 PRINT "We hit your cannon - you're dead!" INPUT "Press M to continue"; ip$ ip$ = ucase$(ip$) LOOP END IF 5.14 CALL RAND ( rand1, rand2, return-value ) ___________________________________________________ Example: CALL RAND ( 10, 39, alien.no ) The CALL RAND GameBasic routine will return in the variable entered for return-value, a random number between the two numbers entered in rand1 and rand2. You will use Random numbers quite a lot in your games. As you can see in our program GAME09.BAS, we used CALL RAND to give us a random number between 10 and 39 (our alien sprite numbers) to select a random alien to fire a fireball. Now, we'll explain the code we added to make it necessary to hit the alien twice before it gets deleted. First, we added a new character definition, char$ ( 5 , n ), to define a different coloured alien. We'll use this new character definition when we first hit the alien. 'Test if any missiles have hit any aliens FOR missile.no = 40 to 44 CALL ACTIVE(missile.no, 0, missile.active) IF missile.active = 1 THEN CALL CHECKHIT(missile.no, 10, 39, 8, alien.no) IF alien.no > 0 THEN CALL INFO(alien.no, row, col, speed,direction,charno,edge$,pixs) IF charno = 2 THEN CALL CHANGECHAR(alien.no, 5) CALL DELETE(missile.no, 0) ELSE CALL DELETE(missile.no, 0) CALL DELETE(alien.no, 0) END IF END IF END IF NEXT missile In the above, when we've hit an alien, the first thing we do is CALL INFO. This command will return information to us about the sprite in question. What we're after here is the character number it is currently being displayed as. If it's being displayed as character number 2 (the regular alien sprite) then we CALL CHANGECHAR to change its character number to character 5 (a different coloured alien sprite). If it's not character number 2, then it must be character number 5, so we delete it. Notice in all the code above, where we have used what we call NESTED IF's, that we always line up the END IF command with the associated IF statement to make our program clearer to read. 5.15 CALL CHANGECHAR ( sprite.no, char.no ) ______________________________________________ Example: CALL CHANGECHAR ( 1, 5 ) This GameBasic command lets you change the character that the sprite is currently being displayed as. Sprite.no - enter the number of the sprite who's character you wish to change. char.no - enter the new character number for the sprite. In our program above, we use this command to change the alien's character from character 2 (the regular character) to character 5 after it has been hit once. Now run this program by pressing F5 (or ALT then R then S). That's it. You've now completed your first game in GameBasic. WELL DONE. You can use what you've learnt to make your own games very easily. Make a copy of this last program, and see if you can change it so that when all the aliens have been shot, the program goes back to the beginning, recreates the alien sprites etc... and plays again, but at a faster speed. See if you can add a SCORE process that adds up number of aliens hit and displays the score on the screen. How about making the alien speeds random, or. . . , or . . , or . . . The possibilities are endless. HAVE FUN. That's what it's all about! (Have a look at program GAME10.BAS !) ___________________________________ 6. ADDITIONAL GAMEBASIC COMMANDS. ___________________________________ The following are additional Gamebasic commands that have not been covered up to this point. 6.1 CALL MOTION (sprite.no,speed,direction, pixspermove) _________________________________________________________ EXAMPLE: CALL MOTION (1, 35, 270, -1) This command changes a sprite's speed and direction. sprite.no - enter the number of the sprite you wish to change. speed - enter the revised speed for this sprite. direction - enter the revised direction (angle) for this sprite. pixspermove - enter the revised pixels per move for this sprite. Enter the value of -1 for any parameter which you don't want to change. In the above example, we're changing speed and direction, but not the sprite's pixels per move. 6.2 CALL GETANGLE ( sprite.no1, sprite.no2, return-value) __________________________________________________________ EXAMPLE: CALL GETANGLE ( 1, 2, new.angle) This command will return the angle between two sprites. sprite.no1 - enter the first sprite number. sprite.no2 - enter the second sprite number. return-value - enter a variable name to receive the value for 'angle' 6.3 CALL MUSIC (type$, length$, tempo$, octave$, notes$) __________________________________________________________ EXAMPLE: CALL MUSIC ( "C" , "L64" , "T255" , "O3" , "ABCDE" ) Introduce a new dimension to your games by adding music and sounds. All the following parameters are string parameters and must therefore be enclosed in quotes (" "). For more details regarding parameter options, please refer to the PLAY instruction in Basic HELP. type$ - There are two types of sounds you can create; one is continuous and will play all the time the game is playing. The other is a single sound (like a missile launching), and will interrupt a continuous sound. "C" = Continuous "S" = Single sound. length$ - The length of each note's duration. Keep the lengths as short as possible (ie high values) otherwise the music will impact the game's speed. "Lnn" where nn is the length; from 1 to 64 tempo$ - The tempo of the music (the number of quarter notes per minute. Keep this as a reasonably high value to minimise impact to your game's speed. "Tnn" where nn is the tempo; from 32 to 255. octave$ - The octave the notes should initially start at. "On" where the O is the letter "Oh" and n is from 0 to 6. notes$ - The actual notes you want to play; ie "ABBD>ACF" Including a ">" or "<" sign in the notes will increase or decrease the octave of following notes. HINT: If you have coded music and you want to turn it off (perhaps your dad's sleeping again!) then use the GameBasic variable gb.music$. Setting this to "N" at the top of your program will turn the music off. Setting it to "Y" will turn music on. 6.4 CALL TEXTSCREEN (Screen.mode,Clear.screen$,Choice$) _______________________________________________________ EXAMPLE: CALL TEXTSCREEN ( 2, "Y", play.again$ ) Use this GameBasic routine to display a menu or text screen from which the player will select a choice. The routine uses a GameBasic array called gb.line$() which has 25 entries, each entry representing the text that you want printed at that line number. Before calling TEXTSCREEN, enter all the valid keys that the user can press into the variable you will be passing to the routine. The routine will then check that a valid key was pressed before returning back to your program. Note in our example above that if play.again$ has a null value (""), or you code CALL TEXTSCREEN(1, "Y", "") then the routine will accept ANY key as a valid key. Screen.mode - Enter the screen mode that you want the text screen to be displayed in. (See Chapter 7.1 for a full discussion on Screen Modes). Valid values: 1 or 2 Note: If you select a screen mode that is different than the one your game is currently using, your game screen will be wiped-out when the text screen is displayed. Clear.screen$ - Enter a value of "Y" or "N" to specify whether you want the current screen to be cleared before the text screen is displayed. Choice$ - Enter all the valid keys that the player can enter in response to your text screen. An entry of null ( "" ) will accept any key as a valid key. An example might be: gb.line$(1) = " My Game Menu " gb.line$(2) = " ------------- " gb.line$(5) = " N - Novice Level" gb.line$(6) = " A - Advanced Level" gb.line$(7) = " E - Expert Level" gb.line$(9) = " X - Exit" level$ = "NAEX" CALL TEXTSCREEN( 2, "Y", level$) IF level$ = "N" THEN ....... Another example might be: gb.line$(15) = "Well done.You have won the Game. " gb.line$(17) = "Play again? Y or N : " continue$ = "YN" CALL TEXTSCREEN( 1, "N", continue$) IF continue$ = "Y" THEN ...... IF continue$ = "N" THEN ....... 6.5 CALL QUESTION (Question.row, Question.col, Answer.row, Answer.col, Question.no, Result$) _____________________________________________________________ Example: CALL QUESTION ( 10, 1, 15, 1, q.no, ans$ ) Gamebasic lets you create question and answer games very easily, also incorporating animated characters to enhance your game. To make such games, you enter your questions into an array called gb.question$, and the correct answer into an array called gb.answer$, then issue the CALL QUESTION command. NOTE: BEFORE YOU START YOUR GAME, OR WHEN YOU RE-START IT, SET THE GAMEBASIC VARIABLE GB.QUEST.OS (QUESTION OUTSTANDING) TO 0. Question.row - This is the row at which the question will print and can be from 1 to 25. Question.col - This is the column at which the question will print and can be from 1 to 79. Answer.row - The row where the answer that the player keys in will be printed. Valid values are from 1 to 25. Answer.col - The column where the answer that the player keys in will be printed. Valid values are from 1 to 79. Question.no - The question number that is to be asked. You can enter up to 300 questions and answers. Result$ - The routine returns one of three values: space - the question is still being answered,player has not yet hit enter. "Y" - The player entered the correct answer "N" - The player entered the wrong answer The following example will illustrate: gb.question$(1) = "What is the capital of France?" gb.answer$(1) = "Paris" gb.question$(2) = "What is the longest river in Africa?" gb.answer$(2) = "Nile" gb.question$(3) = "What is the population of Canada?| a) 2 million | b) 320 million | c) 28 million" gb.answer$(3) = "C 28" end.of.game$ = "N" quest.no = 1 DO WHILE end.of.game$ = "N" CALL MOVE CALL QUESTION(10, 5, 20, 5, quest.no,ans$) IF ans$ = "Y" THEN PRINT "That's right" quest.no = quest.no + 1 score = score + 1 ENDIF IF answer$ = "N" then ....... . LOOP Notice the character "|" in gb.question$(3) above? This is the character above the "\" on your keyboard. Each time this character is encountered while the question is being printed, printing will start on a new line. This question would therefore appear on the screen as follows: What is the population of Canada? a) 2 million b) 320 million c) 28 million? If you want to include a quotation mark in your question, use the single quotation mark - ' The fact that Result$ can contain a space needs a bit of explanation. With this function, you can have animated characters moving around on the screen while the question is being answered - for example, you could have a runner at the top of the screen running towards a series of hurdles. The longer the player takes to answer the question, the closer the runner would get to the first hurdle. If the question isn't answered correctly by the time the runner reaches the first hurdle, your program could make the runner fall down rather than jumping the hurdle. To do this, you have to have the CALL QUESTION line as part of your main program loop, which includes the CALL MOVE routine (which moves the runner) as follows: end.of.game$ = "N" CALL CREATE ( 1, 1, 10, 20, ... . ) 'code to create runner CALL CREATE ( 2, 2, 10, 60, ..... ) ' and hurdles . . . DO WHILE end.of.game$ = "N" CALL MOVE CALL RAND ( 1, 100, quest.no ) CALL QUESTION ( 10, 5, 20, 5, quest.no, ans$ ) IF ans$ = "Y" THEN ...... IF ans$ = "N" THEN ...... ' code to test if runner has reached next hurdle etc.... . . . . LOOP Even though CALL QUESTION is called each time the loop is executed, if a question is still outstanding (ie the "Enter" key has not been pressed) then nothing will happen and the next question will not be asked. However, the CALL MOVE routine will move the runner while the player is entering the answer to the question. Make sure that your program only asks a new question (adding 1 to quest.no) only when the parameter returned by CALL QUESTION (ans$ in the example above) is either "Y" or "N". See the demo program GBDEMO.BAS for an example of how this works. NOTE: Before a new question is asked, the QUESTION routine will automatically clear the screen from the row location of the last question asked to the bottom of the screen. Therefore, if you have graphics on the screen in this area, they will be erased. Also, if you print the answer above the question, it will not get cleared. Try to keep animation to the top of the screen and questions and answers towards the bottom. 6.6 CALL TRACK (Row.or.Col$, start.row.or.col.no, start.no, end.no, width, track$) _____________________________________________________________ Example CALL TRACK( "R", 10, 30, 200, 2, "A" ) With Gamebasic, you can make sprites follow one of 7 tracks (tracks A to F - corresponding to colour codes A to F; and track 0 - the background track) that you can lay down on the screen by using this TRACK routine. If you want a sprite to follow a track then the CALL CREATE command which creates the sprite must specify which track it is to follow. Tracks can have intersections so that when a sprite following a track comes to a junction, it will randomly decide which path to follow. The following 2 tracks explain this: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb b b aaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaa b a b a a b a b a a b a aaaaabaaaaaaaaaaaaaaaa b a a b a b a a b a b aaaaaaaaaaaabbbbbbbbbaa b b b b b bbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbb Each section of track you want to lay down has to be done using the CALL TRACK routine as follows: Row.or.col$ - This is a string parameter which tells Gamebasic whether you are laying down a vertical section of track (ie a Column) or a horizontal section (ie a Row) Valid values are "C" and "R". Start.row.or.col.no - This tells Gamebasic the starting Row or Column number for this section of track. Start.no - If this is laying down a Row track, then this parameter is the starting column number the track should be laid from, otherwise it is the starting Row number. End.no - This is the column or row that the track should end at. Width - This is the width of track that should be laid. Track$ - The track letter that is assigned to this track. Valid values are "0" and "A" to "F". Let's take an example; look at the first line of Track B in the diagram above. Assuming this line is at row 3, and the b's start in column 60 and end in column 200 then if we wanted to draw a track 1 pixel wide we would code: CALL TRACK ( "R", 3, 60, 200, 2, "B" ) In the CALL CREATE command for sprites you want to follow track B, you must make sure that their initial row and column position is on the track. Get the idea? Not too difficult is it? However, there are a few aspects you should be aware of in laying down tracks and initially placing sprites on tracks: A). If you are laying down multiple track numbers, always lay down the lowest track number first, followed by the next lowest after that one, and so on. B). A sprite that is following track B (for example), can also take any higher track if it's upper-left pixel meets that track number in its travels. A sprite following track E, (say) can only follow tracks E and F (if it exists), it can't follow any lower tracks. Sprites following track 0 can only follow track 0 and no higher track numbers. C). You only need to draw a track that is one pixel wide for the sprite to follow it. You can give different tracks different colours on the screen (see the CALL COLOUR command later). You can also make the width wider than one pixel, BUT THE WIDTH MUST NOT EXCEED THE NUMBER OF PIXELS THAT THE SPRITE MOVES EACH TIME (as defined in the CALL CREATE command when the sprite was set up) OTHERWISE IT WILL SPEND MUCH OF ITS TIME MOVING FROM ONE SIDE OF THE TRACK TO THE OTHER RATHER THAN MOVING ALONG THE TRACK. D). The initial positioning of the sprite you want to move along the track and the distance between intersections is very important. When you first create the sprite, if you don't put it on the track you have laid down, it will not move at all - it will just stay where it is flickering! The poor thing can't go anywhere since it's not on the track. E). This next issue is slightly more complex, so let's take an example; Let's suppose we have laid down a track as follows: aaaaaaaaaaaaaaaaaaaaaaaaaaa a a a a This is a pretty simple track. The row of 'a's start in row 1 and the vertical 'a's start in column 5 and 15. Now, if we created our sprite to move 4 pixels per move and initially placed it at row 1 column 3, it would never take the first vertical branch. However, it would take the second branch, since it is defined a multiple of 4 pixels from the initial sprite starting position (col 3 +(4 pixels * 3 moves) = 15). F). Leave the top left screen dot (or pixel) in your character definition for all your track sprites blank and try to ensure (through your track layout and the number of pixels that your sprites move) that in their travels, no sprite's top left pixel coincides with any other sprite's non-blank pixel. HINT: Plan out your tracks, their numbers and intersections carefully before you start programming. If a sprite doesn't move when you put it on a track, you've probably not put it on the track correctly. If it never takes an intersection, it's probably missed it due to the above. 6.7 CALL COLOUR (Colour.code$, colour.name$, blue, green, red ) ___________________________________________________________ Examples CALL COLOUR ( "A", "dragon track", 20, 40, 10 ) CALL COLOUR ( "0", "Background", 10, 10, 34 ) You can select from any of 262,144 colours. Colours are defined as a combination of blue, green and red intensities, with intensity ranging from 0 to 63 for each colour (64 x 64 x 64 = 262,144). Tracks A to F use colour codes A to F. Therefore, if you are using colour code A (for example) in one of your character definitions, and you have also defined a track A, their colours will be the same. Having said this, then each colour in your character and/or track definitions (0 to 9 and A to F) can be custom defined using this routine. For example, you may have used the colour red (number code 4) in a spaceship character. If you wanted to change the colour to a specific hue of red (or even another colour entirely) then you could use this command to do that. However, every other character that uses code 4 in its definition will also have its colour changed. Run program GBCOLOUR.BAS supplied with this program to see examples of other colours available, along with the codes needed to define them. Colour.code$ - This is the background (0 or space) or track/colour number that you wish to custom colour. Colour.name$ - This is for information and program documentation only. Blue - The value of the blue intensity for this colour. Range is from 0 to 63 Green - The same as above, but for Green. Red - The same as above, but for Red. HINT: Initially, when you lay down a track, you'll want to see it clearly to verify that you've got it on the correct place. However, when you run your game, you'll probably not want the tracks to be shown. Use this function to make tracks the same colour as the background, so they'll 'disappear'. 6.8 CALL DISTANCE ( sprite.no1, sprite.no2, distance ) _______________________________________________________ Example: CALL DISTANCE (1, alien.no, dist) The DISTANCE routine returns the distance in pixels between two active sprites. sprite.no1 - The first sprite number sprite.no2 - The second sprite number. distance - A numeric variable into which Gamebasic will return the value of the distance between the two active sprites. If either one is inactive, -1 is returned. 6.9 CALL PAUSE ( number ) ____________________________ Example: CALL PAUSE ( 5 ) The PAUSE routine, as its name implies, pauses your program for a number of seconds. While your program is paused, nothing will happen. However, if you press any key on the keyboard before the pause-time has expired, your program will start up again. If you want to stop your program until any key is pressed, regardless of the time, then use 0 for the number. number - Enter a pause duration in number of seconds. Value must be from 0 to 32000 6.10 CALL COLOURRESET _____________________ Example: CALL COLOURRESET COLOURRESET resets all custom colours you have defined, including the background colour (0) and text-colour (15), back to their original QBasic colours. 6.11 CALL MOVEBACK ( sprite.no ) __________________________________ Example: CALL MOVEBACK ( 10 ) MOVEBACK moves a sprite back to its last screen position. This command is used in the TANK game. When the program detects that a tank is running into a tree, it uses the MOVEBACK command to move the tank back to its last position before it moved into the tree. If the sprite is not active, nothing will happen. You can only move a sprite back ONE move, you can't move it back to its position prior to its last position. sprite.no - Enter a valid sprite number, from 1 to 90. 6.12 CALL PIXELCOLOUR ( sprite.no, top.left, top.right, bottom.left, bottom.right) _______________________________________________________ Example: CALL PIXELCOLOUR ( 12, tl, tr, bl, br ) The PIXELCOLOUR routine returns the colour codes of the pixels at the four extreme corners of the specified sprite on the screen. If you don't define a sprite pixel colour in the extreme corners of your character definition, (for example, the first position in CHAR$(3,1) = "..." , the 16th position in CHAR$(3,1) , the first position in CHAR$(3,12) = "..." and the 16th position in CHAR$(3,12) ) then PIXELCOLOUR will return the colour code on the screen at these locations. This command is used in the TANK demo game to provide a more accurate check as to whether a tank has run into an oil-patch, rather than using the CHECKHIT routine. Sprite.no - Enter the number of the sprite you want to check. top.left, top.right, bottom.left, bottom.right - Enter numeric variables into which the routine will place the colour codes of the pixels on the screen at the specified locations. _____________________________________ 7. MISCELLANEOUS GAMEBASIC FEATURES _____________________________________ 7.1 GB.SCREEN ______________ There are two screen-modes in GameBasic, both controlled by the variable gb.screen. The variable has to be set for your selected screen mode BEFORE you call the DEFINECHAR routine to set up your characters. GB.SCREEN = 1 This is the mode you're already familiar with. In this mode, there are 200 pixels down the screen (from 0 to 199) and 320 pixels across the screen (0 to 319). However, all row and column parameters you enter in your Gamebasic CALL's must not be greater than 187 and 303 respectively. This mode lets you create characters 16 pixels wide and 12 pixels deep, as explained in section 5.3 CHAR$. The definition you're able to get to your characters is limited by the fact that you only have 192 pixels to work with for each character. GB.SCREEN = 2 In this mode, each individual pixel on the screen is smaller than in mode 1 above. There are 480 pixels down the screen (from 0 to 479) and 640 pixels across the screen (0 to 639). However, all row and column parameters you enter in your Gamebasic CALL's must not be greater than 449 and 607 respectively. This mode lets you create characters 32 pixels wide and 30 pixels deep. The character's size will be about the same as those created in screen mode 1, but it's definition will be much higher (more pixels per inch..) The higher density of pixels on the screen and the more pixels you can use to define your character will give you a much better character definition than in screen mode 1. The following is an example of a char$() definition for screen mode 2 characters: char$(1, 1) = " 66 " char$(1, 2) = " 6666 " char$(1, 3) = " 6666666 " char$(1, 4) = " 6668886666 " char$(1, 5) = " 66888118888 " char$(1, 6) = " 888888888 8 " char$(1, 7) = " 888888444 " char$(1, 8) = " 888888888 " char$(1, 9)= " 888888 " char$(1,10) = " 2222222222 " char$(1,11) = " 888855555555555588888 " char$(1,12) = " 8888855555555555555588888 " char$(1,13) = " 888885555555555555555888 " char$(1,14) = " 888885555555555555555588 88 " char$(1,15) = " 558888555555555555558888 8888 " char$(1,16) = " 555588888555555555888888888 " char$(1,17) = " 555588888555555555888888 " char$(1,18) = " 55555555555555555 " char$(1,19) = " 888888 888888 " char$(1,20) = " 888888 888888 " char$(1,21) = " 888888 888888 " char$(1,22) = " 888888 888888 " char$(1,23) = " 888888 888888 " char$(1,24) = "188111 888888 " char$(1,25) = "111111 1888881 " char$(1,26) = " 11111 11111 " char$(1,27) = " 11111 1111 " char$(1,28) = " " char$(1,29) = " " char$(1,30) = " " However, there is a trade-off (as there is with everything!). If you are programming a fast action game, your game's speed will be somewhat slower if you code it in screen mode 2. If speed is not a critical factor in your game, use screen mode 2 to get a better character definition. HINT: When you program your game, set up two variables called R ! and C ! (for row and column), set them to a value of 1, and code your program in gb.screen mode 1. When you include row, column and tolerance parameters in GameBasic calls, code them as 10*R !, 23*C !, etc... (assuming the first parameter was for row 10 and the next was for column 23). Now, when you want to try out how fast the game plays in screen mode 2, all you need to do is change the value of R ! to be 2.4 and change C ! to be 2, change gb.screen = 2 and run your program (your characters will be much smaller until you recode them in the new dimensions). 7.2. GB.SLOWDOWN ________________ If you are lucky enough to be running your game on a very fast computer (ie a 486 or better), you may find that it runs too fast. If this is the case, then set the variable gb.slowdown to a value of between 10 and 32,000 to slow the game down. 7.3. KEY REPEATAMATIC RATE. ___________________________ If, when you hold down a key while you're playing your game, there is an extra-long delay before the key-controlled sprite moves, you may be able to reduce this delay by changing the repeat and delay rate that DOS sets up when the system boots up. To do this, you will need to add the following command to your AUTOEXEC.BAT file and restart your computer: MODE CON: RATE=20 DELAY=1 Note that this may not be feasible if your terminal is on a network. 7.4 SPLIT-SCREEN FEATURE. __________________________ With Gamebasic, you can program your game so that specific sprites only move within certain screen boundaries. Set GameBasic variables gb.screen.start.row, gb.screen.start.col, gb.screen.end.row and gb.screen.end.col to be the screen limits you want before creating the sprites that should move within these limits. Any sprites you CREATE after these variables have been set will then wrap, stay or bounce etc.. within these defined limits.Using this feature, you could program a two-player game where each player plays in his own "window" with his own sprites.... At any time in your game, you can change these variables and create new sprites, with new screen limits, without affecting previously-created sprites. 7.5 USING THE BASIC TIMER IN GAMEBASIC. _________________________________________ In some games that you develop in Gamebasic, you will want to make something happen after a wait of a couple of seconds or more (a period of time measured from a specific event). For example, perhaps you don't want Aliens to fire fireballs until the game has been played for 3 or 4 seconds. Maybe, in another game, you might want to start a helicopter crossing the screen after 1 minute of play. To do this, you will use the Basic TIMER command. Here's how it works. At the point in your program where you want time to be measured from, (maybe just before the game goes into the main program loop?) include an instruction like the following: time.start! = TIMER TIMER is a Basic instruction that returns the number of seconds from midnight to the time in the computer's internal clock at the time the instruction was issued. This is quite a large value, so we have to tell Basic to set up a large variable to contain it - this is what the ! character after the variable named time.start means. If you don't include the ! character, you'll get an error message from Basic when it runs. Next, at the place in our program where we want to start something happening after a number of seconds or minutes have elapsed, include something like the instructions following the CALL MOVE statement: time.start! = TIMER DO WHILE end.of.game$ = "n" CALL MOVE time.now! = TIMER IF time.now! - time.start! > 180 THEN time.start! = time.now! CALL CREATE (.. .. .. ) . (logic to start our special action . happening...) ENDIF The example above will wait until 180 seconds (or 3 minutes, for those of you not too mathematically inclined) have passed since we went into the main program loop before it executes the CALL CREATE logic to start our special action. Notice that once we get into this logic, we reset the variable time.start! to be equal to time.now! (the time that we started our special logic). This would then reactivate our special action code when another 3 minutes have passed. Clever, huh? By the way, seconds can be a decimal value, so if your instruction above said IF time.now! - time.start! > 0.5 THEN ..... then your special action would happen 1/2 a second after the main program loop was entered. APPENDIX A - INKEY Values Key Value Key Value _________________________________________________________ Esc 27 Y 121 F1 59 U 117 F2 60 I 105 F3 61 O 111 F4 62 P 112 F5 63 { 123 F6 64 } 125 F7 65 [ 91 F8 66 ] 93 F9 67 A 97 F10 68 S 115 F11 133 D 100 F12 134 F 102 ~ 126 G 103 ! 33 H 104 @ 64 J 106 # 35 K 107 $ 36 L 108 % 37 Spacebar 32 ^ 94 : 58 & 38 " 34 * 42 ; 59 ( 40 ' 39 ) 41 Z 122 _ 95 X 120 + 43 C 99 | 124 V 118 BKSP 8 B 98 ` 96 N 110 1 49 M 109 2 50 < 60 3 51 > 62 4 52 ? 63 5 53 , 44 6 54 . 46 7 55 / 47 8 56 Insert 82 9 57 Home 71 0 48 Page Up 73 - 45 Delete 83 = 61 End 79 \ 92 Page Down 81 Tab 9 Up Arrow 72 Q 113 Left Arrow 75 W 119 Down Arrow 80 E 101 Right Arrow 77 R 114 Grey + 43 T 116 Grey - 45 CAUTION: THERE ARE DUPLICATE VALUES FOR KEYS F1 TO F6. CALL ACTIVE (sprite.no1, sprite.no2, return-value) To find out how many sprites are active between sprite numbers 10 to 30: CALL ACTIVE(10,30, number.active) CALL CHANGECHAR (sprite.no, char.no) To change sprite number 1's character to character 2: CALL CHANGECHAR (1, 2) CALL CHECKHIT (sprite.no, target.sprite1, target.sprite2, tolerance, return-value) To find out if sprite number 1 has hit any sprites between 10 to 30, with a tolerance of 8 pixels: CALL CHECKHIT (1, 10, 30, 8, sprite.number.hit) CALL COLOUR (Colour.code$, colour.name$, blue, green, red ) To change the background colour: CALL COLOUR("0", "back",10,23,30) To change the colour that text is printed (in PRINT command) CALL COLOUR ("F", "text", 23, 45, 10) CALL COLOURRESET This subroutine has no variables. To reset colours back to original QBasic colours: CALL COLOURRESET CALL CONTROL (sprite.no, horiz$, vert$, pixspermove, "U", keyup, charup,shootdirectup, shootcharup, "D", keydown, chardown,shootdirectdown,shootchardown, "L", keyleft, charleft,shootdirectleft,shootcharleft, "R", keyright,charright,shootdirectright, shootcharright) Example of the CALL CONTROL statement used in the Ducks In Space game: CALL CONTROL(1, "Y", "Y",6, "UP", 72, 8, 0, 3, "DOWN", 80, 9, 180, 5, "LEFT", 75, 10, 270, 6 "RIGHT", 77, 11, 90, 7) CALL CREATE (sprite.no, char.no, col, row, speed, pixspermove, direction, horiz$, vert$, track$) To create sprite # 1 using character #7, starting in col 20, row 30 with a speed of 40 moving straight up (0 degrees) at 5 pixels each time and wrapping around the screen: CALL CREATE (1, 7, 20, 30, 40, 5, 0, "W", "W", " ") CALL DEFINECHAR This subroutine needs no variables. CALL DELETE (sprite.no1, sprite.no2) To delete sprite # 1: CALL DELETE (1,0) To delete sprite #'s 10 to 20: CALL DELETE (10,20) CALL DISTANCE (sprite.no1, sprite.no2, distance ) To find out the distance between sprite #1 and #10: CALL DISTANCE (1, 10, dist) CALL GETANGLE (sprite.no1, sprite.no2, return-value) To get the angle in degrees between sprite # 1 and # 20: CALL GETANGLE (1, 20, angle) CALL INFO (sprite.no, col, row, speed, direction, char.no, hit.edge$, pixspermove) To get information on sprite # 23: CALL INFO (23, c, r, s, d, charno, hitedge$, ppm) CALL MOTION (sprite.no, speed, direction, pixspermove) To change only the direction of sprite #6: CALL MOTION (6, -1, -1, 5, -1) CALL MOVE This subroutine needs no variables. CALL MOVEBACK (sprite.no) To move sprite # 3 back to its position prior to the last move: CALL MOVEBACK (3) CALL MUSIC (type$, length$, tempo$, octave$, notes$) To play the notes ABCDEFG in octave 2 for length 10 and tempo 200: CALL MUSIC("S", "L10", "T200", "O2", "ABCDEFG") CALL PAUSE (number) To pause program for 10 seconds: CALL PAUSE (10) To pause program until any key is pressed: CALL PAUSE ( 0 ) CALL PIXELCOLOUR (sprite.no, top.left, top.right, bottom.left,bottom.right) To query the pixels at extreme corners of sprite # 4: CALL PIXELCOLOUR ( 4, tl, tr, bl, br ) CALL QUESTION (Question.row, Question.col, Answer.row, Answer.col, Question.no, Result$) To display a question at row 10, column 30 and answer at row 15, column 30: CALL QUESTION (10, 30, 15, 30, quest.no, right.or.wrong$) CALL RAND (rand1, rand2, return-value) To get a random number between 1 and 10: CALL RAND (1, 10, rand.num) CALL SHOOT (sprite.no, charno, from.spriteno, to.spriteno, speed, pixspermove, horiz$, vert$) To create sprite # 12 as a missile (character # 40) to be shot from sprite #3 to sprite #40 at a speed of 35 and 6 pixelspermove, and for the missile to get deleted at any screen border: CALL SHOOT (12, 40, 3, 40, 35, 6, "D", "D") CALL TEXTSCREEN (screen.mode, clear.screen$, choice$) To print "Want to play again? Y/N : " in screen mode 2 at row 20, column 10 without deleting the screen: gb.line$(20) = "Want to play again? Y/N : " choice$ = "YN" CALL TEXTSCREEN ( 2, "N",choice$) IF choice$ = "Y" THEN . . . . . CALL TRACK (Row.or.Col$, start.row.or.col.no, start.no, end.no, width, track$) To write a row track using track C to the screen at row 10, starting in column 30, ending in column 300 for 2 pixels wide: CALL TRACK ("R", 10, 30, 300, 2, "C") F 1 : TOPIC HELP Provides help screens on the QBasic command which the cursor is under. F 3 : REPEAT FIND If you use the Alt + S(earch) + F(ind) feature of QBasic to find all occurrences in your program of a specific character string, then the F3 key will find the next occurrence. F4 : OUTPUT SCREEN. Toggle between the program edit screen and the output screen. Shift + F5 RUN PROGRAM Run program from start. F5 : CONTINUE PROGRAM If you have paused the program with an F9 breakpoint or pressed CTRL-Break, you can start the program running again from the place it stopped by pressing F5. F6 : IMMEDIATE WINDOW. QBasic provides a window at the bottom of the program edit screen into which you can code QBasic commands. You toggle in and out of this window by pressing F6. For example, if you were debugging your program and had it paused and wanted to see what was in a particular variable you could press F6 to access the Immediate window, then enter LOCATE 10,20 : PRINT variable.name , then flip to the output screen using the F4 key to see what was printed. You can also change the contents of your program's variables while the program is paused using this feature. However, since there is a high possibility that the screen output you create through this immediate window will upset the position of your sprites on the screen, use this feature with caution. F8 : INSTRUCTION STEP While debugging your program, do the next highlighted instruction only. F9 : TOGGLE BREAKPOINT. In the program edit screen, set a breakpoint on the current line. If one is already set, pressing F9 will turn it off. F10 : Like F8, but if the highlighted instruction is a CALL xxxxxx or GOSUB, Basic will process all code in the procedure before it breaks again.